diff --git a/dlls/kernel/instr.c b/dlls/kernel/instr.c index df52b44bb3c..c67e18333f3 100644 --- a/dlls/kernel/instr.c +++ b/dlls/kernel/instr.c @@ -779,12 +779,6 @@ DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context ) 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 */ diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index e271fcae91d..c325994f431 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -595,9 +595,11 @@ static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext ) * * 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 @@ static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext ) 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; @@ -977,22 +1016,6 @@ static void set_vm86_pend( CONTEXT *context ) 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. - */ - } } diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c index 96faff56ebe..2b3e4c11708 100644 --- a/dlls/winedos/dosvm.c +++ b/dlls/winedos/dosvm.c @@ -227,17 +227,6 @@ void DOSVM_SendQueuedEvents( CONTEXT86 *context ) #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()) { /* diff --git a/dlls/winedos/relay.c b/dlls/winedos/relay.c index ab3f1277ed1..ae6ca09362d 100644 --- a/dlls/winedos/relay.c +++ b/dlls/winedos/relay.c @@ -157,17 +157,6 @@ void DOSVM_RelayHandler( CONTEXT86 *context ) 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 ); - } }