diff --git a/changelog.txt b/changelog.txt index c6280fd59c..2066a050af 100644 --- a/changelog.txt +++ b/changelog.txt @@ -65,6 +65,7 @@ Version 1.10.0 - In normal build of fbc, try to automatically use gcc to query the search path for a std c++ library. This helps with dependency for tests/cpp and for some users that want to interop with c++ - Add makefile option DISABLE_STDCXX_PATH to disable usnig gcc to search for some c++ library path - fbc: allow typename.member symbol checks for #ifdef / #ifndef / defined() where member can be a data field, static data field, nested type, constructor, destructor, property, operator (self-assignment, new, new[], delete, delete[], let, cast, for, step, next), or member procedure. +- rtlib: dos: add "__fb_dos_no_dpmi_yield" variable to control calling "__dpmi_yield()" and prevent a crash under some dos extenders in dosbox [fixed] - gas64: missing restoring of use of one virtual register on sqr for float (SARG) diff --git a/examples/DOS/gfxsleep.bas b/examples/DOS/gfxsleep.bas new file mode 100644 index 0000000000..dadb45df4b --- /dev/null +++ b/examples/DOS/gfxsleep.bas @@ -0,0 +1,57 @@ +#include once "fbgfx.bi" + +extern "c" + extern as unsigned long __fb_dos_no_dpmi_yield +end extern + +'' tells SLEEP to call usleep_private() which does not yeild to dpmi +'' this prevents djgpp c runtime from call __dmpi_yeild() during a +'' call in SLEEP. Disabling this behaviour appears to prevent the +'' program from crashing at least in dosbox with some extenders. + +__fb_dos_no_dpmi_yield = 1 + +screen 13 + +dim as long w, h +ScreenControl fb.GET_SCREEN_SIZE, w, h + +dim as single maxtime = 100 +dim as single x = 10, y = 10, dx = 50, dy = 0, r = 10 +dim as double t0 = timer, t1 = t0, t2 = 0, td = 0.0001 +dim as string k + +do while( t1 - t0 < maxtime ) + + k = inkey + select case k + case chr(27) + exit do + end select + + dy += td * 200 + x += dx * td + y += dy * td + + if( (dx > 0) and (x > w - r) ) then + dx *= -1 + elseif( (dx < 0) and (x < r) ) then + dx *= -1 + end if + + if( (dy > 0) and (y > h - r - r) ) then + dy *= -1 * 0.9 + end if + + circle ( x, y ), r + + sleep 15, 1 + + t2 = timer + td = t2 - t1 + t1 =t2 +loop + +cls +print "exiting" +sleep 1000, 1 diff --git a/src/rtlib/dos/symb_reg.txt b/src/rtlib/dos/symb_reg.txt index a890f8d034..37c6ba296a 100644 --- a/src/rtlib/dos/symb_reg.txt +++ b/src/rtlib/dos/symb_reg.txt @@ -467,6 +467,7 @@ extern_asm(_fb_Now); extern_asm(_fb_ConsoleGetTopRow); extern_asm(_fb_OCTEx_b); extern_asm(_fb_SetDate); +extern_asm(___fb_dos_no_dpmi_yield); extern_asm(_fb_WstrHexEx_l); extern_asm(_fb_DatePart); extern_asm(_fb_InputDouble); @@ -1304,6 +1305,7 @@ DXE_EXPORT_TABLE (libfb_symbol_table) DXE_EXPORT_ASM (_fb_ConsoleGetTopRow) DXE_EXPORT_ASM (_fb_OCTEx_b) DXE_EXPORT_ASM (_fb_SetDate) + DXE_EXPORT_ASM (___fb_dos_no_dpmi_yield) DXE_EXPORT_ASM (_fb_WstrHexEx_l) DXE_EXPORT_ASM (_fb_DatePart) DXE_EXPORT_ASM (_fb_InputDouble) diff --git a/src/rtlib/dos/sys_delay.c b/src/rtlib/dos/sys_delay.c index 662ff0ff55..70f7b8f160 100644 --- a/src/rtlib/dos/sys_delay.c +++ b/src/rtlib/dos/sys_delay.c @@ -3,12 +3,62 @@ #include "../fb_private_thread.h" #endif #include +#include +#include + + +/* __fb_dos_no_dpmi_yield + * - 0 (default), __dpmi_yield() is called in the busy loop for delays + * - non-zero, do not call __dpmi_yield() which seems will prevent + * crashes under some dos extenders + * + * in fb: + * extern "c" + * extern as unsigned long __fb_dos_no_dpmi_yield + * end extern + * __fb_dos_no_dpmi_yield = 1 + */ + +extern unsigned int __fb_dos_no_dpmi_yield; +unsigned int __fb_dos_no_dpmi_yield = 0; + +#if !defined(ENABLE_MT) + +/* usleep() copied from djgpp libc implementation */ +static unsigned int usleep_private(unsigned int _useconds) +{ + clock_t cl_time; + clock_t start_time = clock(); + + /* 977 * 1024 is about 1e6. The funny logic keeps the math from + overflowing for large _useconds */ + _useconds >>= 10; + cl_time = _useconds * CLOCKS_PER_SEC / 977; + + while (1) + { + clock_t elapsed = clock() - start_time; + if (elapsed >= cl_time) + { + break; + } + } + return 0; +} +#endif /* !defined(ENABLE_MT) */ FBCALL void fb_Delay( int msecs ) { #if defined ENABLE_MT - __pthread_usleep(msecs * 1000); + __pthread_usleep(msecs * 1000); #else - usleep(msecs * 1000); + if( __fb_dos_no_dpmi_yield ) + { + usleep_private(msecs * 1000); + } + else + { + usleep(msecs * 1000); + } #endif }