This patch should make DPMI async event handling race-free again after instruction emulation changes which caused instruction emulation to happen with all signals unblocked. Event handling actually gets simpler because there will be only one place where EXCEPTION_VM86_STI will be raised. However, signal return path gets slightly more complicated. V86 signal handling is still somewhat broken and probably unnecessarily complicated but that is something I'm not going to fix for a while. Changelog: Remove races from DPMI async event handling. Index: dlls/ntdll/signal_i386.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v retrieving revision 1.71 diff -u -r1.71 signal_i386.c --- dlls/ntdll/signal_i386.c 8 Oct 2003 22:59:22 -0000 1.71 +++ dlls/ntdll/signal_i386.c 11 Oct 2003 17:44:51 -0000 @@ -595,9 +595,11 @@ * * Build a sigcontext from the register values. */ -static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext ) +static void restore_context( CONTEXT *context, SIGCONTEXT *sigcontext ) { #ifdef __HAVE_VM86 + BOOL check_pending = TRUE; + /* check if exception occurred in vm86 mode */ if ((void *)EIP_sig(sigcontext) == vm86_return && IS_SELECTOR_SYSTEM(CS_sig(sigcontext)) && @@ -610,6 +612,43 @@ restore_vm86_context( context, vm86 ); return; } + + while (NtCurrentTeb()->dpmi_vif && + !IS_SELECTOR_SYSTEM(context->SegCs) && + !IS_SELECTOR_SYSTEM(context->SegSs) && + check_pending) + { + /* + * Executing DPMI code and virtual interrupts are enabled. + * We must block signals so that we can be safely check + * for pending asynchronous events. Return from signal handler + * will unblock signals again so it is is safe to do so. + */ + SIGNAL_Block(); + check_pending = FALSE; + + if (NtCurrentTeb()->vm86_pending) + { + EXCEPTION_RECORD rec; + + rec.ExceptionAddress = (LPVOID)context->Eip; + rec.ExceptionCode = EXCEPTION_VM86_STI; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.NumberParameters = 1; + rec.ExceptionInformation[0] = 0; + + NtCurrentTeb()->vm86_pending = 0; + EXC_RtlRaiseException( &rec, context ); + + /* + * EXC_RtlRaiseException has unblocked all signals + * and we must retry check for pending asynchronous + * events in order to prevent races. + */ + check_pending = TRUE; + } + } #endif /* __HAVE_VM86 */ EAX_sig(sigcontext) = context->Eax; @@ -976,22 +1015,6 @@ teb->vm86_ptr = vm86; restore_vm86_context( &vcontext, vm86 ); } - } - else if(teb->dpmi_vif && - !IS_SELECTOR_SYSTEM(context->SegCs) && - !IS_SELECTOR_SYSTEM(context->SegSs)) - { - /* Executing DPMI code and virtual interrupts are enabled. */ - teb->vm86_pending = 0; - rec.ExceptionAddress = (LPVOID)context->Eip; - EXC_RtlRaiseException( &rec, context ); - /* - * EXC_RtlRaiseException has unblocked all signals and this - * signal handler is about to return to either DOS relay or - * IRQ handler. Because both of these will check pending - * interrupts again, it is not a problem if we receive - * a nested SIGUSR2 here and ignore it. - */ } } Index: dlls/winedos/relay.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/relay.c,v retrieving revision 1.5 diff -u -r1.5 relay.c --- dlls/winedos/relay.c 27 Aug 2003 02:52:18 -0000 1.5 +++ dlls/winedos/relay.c 11 Oct 2003 17:44:57 -0000 @@ -157,17 +157,6 @@ ERR( "Stack corrupted!\n" ); stack->inuse = 0; - - /* - * We have now restored original stack and instruction pointers. - * Because signals are blocked here, this is a safe place to - * check for pending events before we return to application context. - */ - if (NtCurrentTeb()->vm86_pending && NtCurrentTeb()->dpmi_vif) - { - NtCurrentTeb()->vm86_pending = 0; - DOSVM_SendQueuedEvents( context ); - } } Index: dlls/kernel/instr.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/instr.c,v retrieving revision 1.3 diff -u -r1.3 instr.c --- dlls/kernel/instr.c 17 Sep 2003 22:45:46 -0000 1.3 +++ dlls/kernel/instr.c 11 Oct 2003 17:45:04 -0000 @@ -779,12 +779,6 @@ case 0xfb: /* sti */ NtCurrentTeb()->dpmi_vif = 1; context->Eip += prefixlen + 1; - if (NtCurrentTeb()->vm86_pending) - { - NtCurrentTeb()->vm86_pending = 0; - rec->ExceptionCode = EXCEPTION_VM86_STI; - return ExceptionContinueSearch; - } return ExceptionContinueExecution; } return ExceptionContinueSearch; /* Unable to emulate it */ Index: dlls/winedos/dosvm.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v retrieving revision 1.53 diff -u -r1.53 dosvm.c --- dlls/winedos/dosvm.c 30 Sep 2003 00:22:12 -0000 1.53 +++ dlls/winedos/dosvm.c 11 Oct 2003 17:45:10 -0000 @@ -227,17 +227,6 @@ #ifdef MZ_SUPPORTED - if (!ISV86(context) && context->SegCs == old_cs && context->Eip == old_ip) - { - /* - * Routine was called from DPMI but there was nothing to do. - * We force a dummy relay call here so that we don't get a race - * if signals are unblocked when we return to DPMI application. - */ - TRACE( "Called but there was nothing to do, calling NULL relay.\n" ); - DOSVM_BuildCallFrame( context, NULL, NULL ); - } - if (DOSVM_HasPendingEvents()) { /* -- Jukka Heinonen <http://www.iki.fi/jhei/>