Well, it looked like I got all the race conditions fixed in this thing a few weeks ago, may as well submit it now. (I could have made this code a lot simpler if the vm86 syscall would check for VIF|VIP on entry by itself, but noo, so I still need to throw from the signal handler...) For some reason DOS games still performed quite bad in my restructured code last time I checked (possibly a number of SIGALRMs are just lost or something), but perhaps I should just submit that DOS restructure anyway, might be better than nothing? Log: Fixed vm86_enter race conditions. Index: include/thread.h =================================================================== RCS file: /home/wine/wine/include/thread.h,v retrieving revision 1.56 diff -u -r1.56 thread.h --- include/thread.h 2001/11/30 18:46:46 1.56 +++ include/thread.h 2001/12/28 08:23:52 @@ -101,11 +101,10 @@ DWORD alarms; /* --3 22c Data for vm86 mode */ DWORD vm86_pending; /* --3 230 Data for vm86 mode */ void *vm86_ptr; /* --3 234 Data for vm86 mode */ - void *vm86_ctx; /* --3 238 Data for vm86 mode */ /* here is plenty space for wine specific fields (don't forget to change pad6!!) */ /* the following are nt specific fields */ - DWORD pad6[623]; /* --n 23c */ + DWORD pad6[624]; /* --n 23c */ UNICODE_STRING StaticUnicodeString; /* -2- bf8 used by advapi32 */ USHORT StaticUnicodeBuffer[261]; /* -2- c00 used by advapi32 */ DWORD pad7; /* --n e0c */ Index: dlls/ntdll/signal_i386.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v retrieving revision 1.30 diff -u -r1.30 signal_i386.c --- dlls/ntdll/signal_i386.c 2001/10/28 21:16:22 1.30 +++ dlls/ntdll/signal_i386.c 2001/12/28 08:23:53 @@ -115,13 +115,16 @@ } #endif -int vm86_enter( struct vm86plus_struct *ptr ); -void vm86_return(); +#define VM86_EAX 0 /* the %eax value while vm86_enter is executing */ + +int vm86_enter(void); +void vm86_return(void); +void vm86_return_end(void); __ASM_GLOBAL_FUNC(vm86_enter, "pushl %ebp\n\t" "movl %esp, %ebp\n\t" "movl $166,%eax\n\t" /*SYS_vm86*/ - "movl 8(%ebp),%ecx\n\t" + ".byte 0x64\n\tmovl (0x234),%ecx\n\t" /* vm86_ptr */ "pushl %ebx\n\t" "movl $1,%ebx\n\t" /*VM86_ENTER*/ "pushl %ecx\n\t" /* put vm86plus_struct ptr somewhere we can find it */ @@ -134,6 +137,16 @@ "popl %ecx\n\t" "popl %ebx\n\t" "popl %ebp\n\t" + "testl %eax,%eax\n\t" + "jl 0f\n\t" + "cmpb $0,%al\n\t" /* VM86_SIGNAL */ + "je " __ASM_NAME("vm86_enter") "\n\t" + "0:\n\t" + "xorl %ecx,%ecx\n\t" + ".byte 0x64\n\tmovl %ecx,(0x234)\n\t" /* vm86_ptr */ + ".globl " __ASM_NAME("vm86_return_end") "\n\t" + ".type " __ASM_NAME("vm86_return_end") ",@function\n" + __ASM_NAME("vm86_return_end") ":\n\t" "ret" ); #define __HAVE_VM86 @@ -474,14 +487,18 @@ #ifdef __HAVE_VM86 else if ((void *)EIP_sig(sigcontext) == vm86_return) /* vm86 mode */ { - /* retrieve pointer to vm86plus struct that was stored in vm86_enter */ - struct vm86plus_struct *vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int)); /* fetch the saved %fs on the stack */ fs = *(unsigned int *)ESP_sig(sigcontext); - __set_fs(fs); - /* get context from vm86 struct */ - save_vm86_context( context, vm86 ); - return; + if (EAX_sig(sigcontext) == VM86_EAX) { + struct vm86plus_struct *vm86; + __set_fs(fs); + /* retrieve pointer to vm86plus struct that was stored in vm86_enter + * (but we could also get if from teb->vm86_ptr) */ + vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int)); + /* get context from vm86 struct */ + save_vm86_context( context, vm86 ); + return; + } } #endif /* __HAVE_VM86 */ @@ -519,9 +536,11 @@ #ifdef __HAVE_VM86 /* check if exception occurred in vm86 mode */ if ((void *)EIP_sig(sigcontext) == vm86_return && - IS_SELECTOR_SYSTEM(CS_sig(sigcontext))) + IS_SELECTOR_SYSTEM(CS_sig(sigcontext)) && + EAX_sig(sigcontext) == VM86_EAX) { - /* retrieve pointer to vm86plus struct that was stored in vm86_enter */ + /* retrieve pointer to vm86plus struct that was stored in vm86_enter + * (but we could also get it from teb->vm86_ptr) */ struct vm86plus_struct *vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int)); restore_vm86_context( context, vm86 ); return; @@ -807,8 +826,10 @@ if (context->EFlags & VIF_MASK) { /* VIF is set, throw exception */ teb->vm86_pending = 0; + teb->vm86_ptr = NULL; rec.ExceptionAddress = (LPVOID)context->Eip; EXC_RtlRaiseException( &rec, context ); + teb->vm86_ptr = vm86; } } else if (vm86) @@ -816,18 +837,22 @@ /* not in VM86, but possibly setting up for it */ if (vm86->regs.eflags & VIP_MASK) return; vm86->regs.eflags |= VIP_MASK; + if (((char*)context->Eip >= (char*)vm86_return) && + ((char*)context->Eip <= (char*)vm86_return_end) && + (VM86_TYPE(context->Eax) != VM86_SIGNAL)) { + /* exiting from VM86, can't throw */ + return; + } if (vm86->regs.eflags & VIF_MASK) { /* VIF is set, throw exception */ CONTEXT vcontext; teb->vm86_pending = 0; + teb->vm86_ptr = NULL; save_vm86_context( &vcontext, vm86 ); rec.ExceptionAddress = (LPVOID)vcontext.Eip; EXC_RtlRaiseException( &rec, &vcontext ); + teb->vm86_ptr = vm86; restore_vm86_context( &vcontext, vm86 ); - if (teb->vm86_ctx) { - /* must also save here */ - *(CONTEXT*)(teb->vm86_ctx) = vcontext; - } } } } @@ -1065,7 +1090,7 @@ do { - res = vm86_enter( &vm86 ); + res = vm86_enter(); /* uses and clears teb->vm86_ptr */ if (res < 0) { errno = -res; @@ -1073,10 +1098,7 @@ } } while (VM86_TYPE(res) == VM86_SIGNAL); - teb->vm86_ctx = context; save_vm86_context( context, &vm86 ); - teb->vm86_ptr = NULL; - teb->vm86_ctx = NULL; context->EFlags |= teb->vm86_pending; switch(VM86_TYPE(res))