Skip to content

Commit

Permalink
rtlib: dos: optional run-time replacement of usleep
Browse files Browse the repository at this point in the history
- control call of __dpmi_yield() to prevent crashes under some dos extenders in dosbox
- add extern  __fb_dos_no_dpmi_yield  to control calling of __dpmi_yield()
- set __fb_dos_no_dpmi_yield = 1 from user program to call usleep_private() internally
  instead of the usual usleep()
- see example in ./examples/DOS/gfxsleep.bas
  • Loading branch information
jayrm committed Mar 25, 2023
1 parent 2fa2679 commit 4220fc3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Expand Up @@ -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)
Expand Down
57 changes: 57 additions & 0 deletions 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
2 changes: 2 additions & 0 deletions src/rtlib/dos/symb_reg.txt
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
54 changes: 52 additions & 2 deletions src/rtlib/dos/sys_delay.c
Expand Up @@ -3,12 +3,62 @@
#include "../fb_private_thread.h"
#endif
#include <unistd.h>
#include <time.h>
#include <dpmi.h>


/* __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
}

0 comments on commit 4220fc3

Please sign in to comment.