diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c index f8338b9c2b..a8a439c492 100644 --- a/dlls/winedos/dosvm.c +++ b/dlls/winedos/dosvm.c @@ -31,7 +31,7 @@ #include "file.h" #include "miscemu.h" #include "dosexe.h" -#include "../../loader/dos/dosmod.h" +#include "dosvm.h" #include "stackframe.h" #include "debugtools.h" @@ -67,68 +67,11 @@ typedef struct _DOSEVENT { struct _DOSEVENT *next; } DOSEVENT, *LPDOSEVENT; +static CRITICAL_SECTION qcrit = CRITICAL_SECTION_INIT("DOSVM"); static struct _DOSEVENT *pending_event, *current_event; -static int sig_sent, entered; +static int sig_sent; static CONTEXT86 *current_context; -/* from module.c */ -extern int read_pipe, write_pipe; -extern HANDLE hReadPipe; -extern pid_t dosmod_pid; - -static void do_exception( int signal, CONTEXT86 *context ) -{ - EXCEPTION_RECORD rec; - if ((signal == SIGTRAP) || (signal == SIGHUP)) - { - rec.ExceptionCode = EXCEPTION_BREAKPOINT; - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - } - else - { - rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; /* generic error */ - rec.ExceptionFlags = EH_NONCONTINUABLE; - } - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context->Eip; - rec.NumberParameters = 0; - EXC_RtlRaiseException( &rec, context ); -} - -static void DOSVM_Dump( int fn, int sig, struct vm86plus_struct*VM86 ) -{ - BYTE*inst; - int x; - - switch (VM86_TYPE(fn)) { - case VM86_SIGNAL: - printf("Trapped signal %d\n",sig); break; - case VM86_UNKNOWN: - printf("Trapped unhandled GPF\n"); break; - case VM86_INTx: - printf("Trapped INT %02x\n",VM86_ARG(fn)); break; - case VM86_STI: - printf("Trapped STI\n"); break; - case VM86_PICRETURN: - printf("Trapped due to pending PIC request\n"); break; - case VM86_TRAP: - printf("Trapped debug request\n"); break; - default: - printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn),VM86_ARG(fn)); break; - } -#define REGS VM86->regs - fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ecx,REGS.edx,REGS.ebx); - fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp); - fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss); - fprintf(stderr,"IP=%04lX EFLAGS=%08lX\n",REGS.eip,REGS.eflags); - - inst = PTR_REAL_TO_LIN( REGS.cs, REGS.eip ); -#undef REGS - printf("Opcodes:"); - for (x=0; x<8; x++) printf(" %02x",inst[x]); - printf("\n"); -} - static int DOSVM_SimulateInt( int vect, CONTEXT86 *context, BOOL inwine ) { FARPROC16 handler=DOSVM_GetRMHandler(vect); @@ -160,6 +103,8 @@ static int DOSVM_SimulateInt( int vect, CONTEXT86 *context, BOOL inwine ) WORD*stack= PTR_REAL_TO_LIN( context->SegSs, context->Esp ); WORD flag=LOWORD(context->EFlags); + TRACE_(int)("invoking hooked interrupt %02x at %04x:%04x\n", vect, + SELECTOROF(handler), OFFSETOF(handler)); if (IF_ENABLED(context)) flag|=IF_MASK; else flag&=~IF_MASK; @@ -221,7 +166,8 @@ void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data { LPDOSEVENT event, cur, prev; - if (entered) { + if (current_context) { + EnterCriticalSection(&qcrit); event = malloc(sizeof(DOSEVENT)); if (!event) { ERR("out of memory allocating event entry\n"); @@ -240,15 +186,16 @@ void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data event->next = cur; if (prev) prev->next = event; else pending_event = event; - - /* get dosmod's attention to the new event, if necessary */ + + /* alert the vm86 about the new event */ if (!sig_sent) { - TRACE("new event queued, signalling dosmod\n"); - kill(dosmod_pid,SIGUSR2); + TRACE("new event queued, signalling (time=%ld)\n", GetTickCount()); + kill(dosvm_pid,SIGUSR2); sig_sent++; } else { - TRACE("new event queued\n"); + TRACE("new event queued (time=%ld)\n", GetTickCount()); } + LeaveCriticalSection(&qcrit); } else { /* DOS subsystem not running */ /* (this probably means that we're running a win16 app @@ -264,105 +211,6 @@ void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data } } -#define CV do { CP(eax,Eax); CP(ecx,Ecx); CP(edx,Edx); CP(ebx,Ebx); \ - CP(esi,Esi); CP(edi,Edi); CP(esp,Esp); CP(ebp,Ebp); \ - CP(cs,SegCs); CP(ds,SegDs); CP(es,SegEs); \ - CP(ss,SegSs); CP(fs,SegFs); CP(gs,SegGs); \ - CP(eip,Eip); CP(eflags,EFlags); } while(0) - -static int DOSVM_Process( int fn, int sig, struct vm86plus_struct*VM86 ) -{ - CONTEXT86 context, *old_context; - int ret=0; - -#define CP(x,y) context.y = VM86->regs.x - CV; -#undef CP - if (VM86_TYPE(fn)==VM86_UNKNOWN) { - ret=INSTR_EmulateInstruction(&context); -#define CP(x,y) VM86->regs.x = context.y - CV; -#undef CP - if (ret) return 0; - ret=0; - } -#ifdef TRY_PICRETURN - if (VM86->vm86plus.force_return_for_pic) { - SET_PEND(&context); - } -#else - /* linux doesn't preserve pending flag on return */ - if (SHOULD_PEND(pending_event)) { - SET_PEND(&context); - } -#endif - - old_context = current_context; - current_context = &context; - - switch (VM86_TYPE(fn)) { - case VM86_SIGNAL: - TRACE("DOS module caught signal %d\n",sig); - if ((sig==SIGALRM) || (sig==SIGUSR2)) { - if (sig==SIGALRM) { - sig_sent++; - DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL); - } - if (pending_event) { - TRACE("setting Pending flag, interrupts are currently %s\n", - IF_ENABLED(&context) ? "enabled" : "disabled"); - SET_PEND(&context); - DOSVM_SendQueuedEvents(&context); - } else { - TRACE("no events are pending, clearing Pending flag\n"); - CLR_PEND(&context); - } - sig_sent--; - } - else if ((sig==SIGHUP) || (sig==SIGILL) || (sig==SIGSEGV)) { - do_exception( sig, &context ); - } else { - DOSVM_Dump(fn,sig,VM86); - ret=-1; - } - break; - case VM86_UNKNOWN: /* unhandled GPF */ - DOSVM_Dump(fn,sig,VM86); - do_exception( SIGSEGV, &context ); - break; - case VM86_INTx: - if (TRACE_ON(relay)) - DPRINTF("Call DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip); - ret=DOSVM_SimulateInt(VM86_ARG(fn),&context,FALSE); - if (TRACE_ON(relay)) - DPRINTF("Ret DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip); - break; - case VM86_STI: - IF_SET(&context); - /* case VM86_PICRETURN: */ - TRACE("DOS task enabled interrupts %s events pending, sending events\n", IS_PEND(&context)?"with":"without"); - DOSVM_SendQueuedEvents(&context); - break; - case VM86_TRAP: - do_exception( SIGTRAP, &context ); - break; - default: - DOSVM_Dump(fn,sig,VM86); - ret=-1; - } - - current_context = old_context; - -#define CP(x,y) VM86->regs.x = context.y - CV; -#undef CP -#ifdef TRY_PICRETURN - VM86->vm86plus.force_return_for_pic = IS_PEND(&context) ? 1 : 0; - CLR_PEND(&context); -#endif - return ret; -} - static void DOSVM_ProcessConsole(void) { INPUT_RECORD msg; @@ -488,80 +336,123 @@ chk_console_input: } while (TRUE); } -/*********************************************************************** - * Enter (WINEDOS.@) - */ -INT WINAPI DOSVM_Enter( CONTEXT86 *context ) +DWORD WINAPI DOSVM_Loop( LPVOID lpExtra ) { - struct vm86plus_struct VM86; - int stat,len,sig; + HANDLE obj = GetStdHandle(STD_INPUT_HANDLE); + MSG msg; + DWORD waitret; - memset(&VM86, 0, sizeof(VM86)); -#define CP(x,y) VM86.regs.x = context->y - CV; -#undef CP - if (VM86.regs.eflags & IF_MASK) - VM86.regs.eflags |= VIF_MASK; - - /* main exchange loop */ - entered++; - do { - TRACE_(module)("thread is: %lx\n",GetCurrentThreadId()); - stat = VM86_ENTER; - errno = 0; - /* transmit VM86 structure to dosmod task */ - if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) { - ERR_(module)("dosmod sync lost, errno=%d, fd=%d, pid=%d\n",errno,write_pipe,getpid()); - return -1; - } - if (write(write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) { - ERR_(module)("dosmod sync lost, errno=%d\n",errno); - return -1; - } - /* wait for response, doing other things in the meantime */ - DOSVM_Wait(read_pipe, hReadPipe); - /* read response */ - while (1) { - if ((len=read(read_pipe,&stat,sizeof(stat)))==sizeof(stat)) break; - if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { - WARN_(module)("rereading dosmod return code due to errno=%d, result=%d\n",errno,len); - continue; + for(;;) { + TRACE_(int)("waiting for action\n"); + waitret = MsgWaitForMultipleObjects(1, &obj, FALSE, INFINITE, QS_ALLINPUT); + if (waitret == WAIT_OBJECT_0) { + DOSVM_ProcessConsole(); } - ERR_(module)("dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len); - return -1; - } - TRACE_(module)("dosmod return code=%d\n",stat); - if (stat==DOSMOD_LEFTIDLE) { - continue; - } - while (1) { - if ((len=read(read_pipe,&VM86,sizeof(VM86)))==sizeof(VM86)) break; - if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { - WARN_(module)("rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno,len); - continue; - } - ERR_(module)("dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno,len); - return -1; - } - if ((stat&0xff)==DOSMOD_SIGNAL) { - while (1) { - if ((len=read(read_pipe,&sig,sizeof(sig)))==sizeof(sig)) break; - if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { - WARN_(module)("rereading dosmod signal due to errno=%d, result=%d\n",errno,len); - continue; + else if (waitret == WAIT_OBJECT_0 + 1) { + GetMessageA(&msg, 0, 0, 0); + if (msg.hwnd) { + /* it's a window message */ + DOSVM_ProcessMessage(&msg); + DispatchMessageA(&msg); + } else { + /* it's a thread message */ + switch (msg.message) { + case WM_QUIT: + /* stop this madness!! */ + return 0; + case WM_USER: + /* run passed procedure in this thread */ + /* (sort of like APC, but we signal the completion) */ + { + DOS_SPC *spc = (DOS_SPC *)msg.lParam; + TRACE_(int)("calling %p with arg %08x\n", spc->proc, spc->arg); + (spc->proc)(spc->arg); + TRACE_(int)("done, signalling event %d\n", msg.wParam); + SetEvent(msg.wParam); + } + break; + } } - ERR_(module)("dosmod sync lost reading signal, errno=%d, result=%d\n",errno,len); - return -1; - } while (0); - } else sig=0; - /* got response */ - } while (DOSVM_Process(stat,sig,&VM86)>=0); - entered--; + } + else break; + } + return 0; +} -#define CP(x,y) context->y = VM86.regs.x - CV; -#undef CP - return 0; +static WINE_EXCEPTION_FILTER(exception_handler) +{ + EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord; + CONTEXT *context = GetExceptionInformation()->ContextRecord; + int ret, arg = rec->ExceptionInformation[0]; + + switch(rec->ExceptionCode) { + case EXCEPTION_VM86_INTx: + if (TRACE_ON(relay)) { + DPRINTF("Call DOS int 0x%02x ret=%04lx:%04lx\n", + arg, context->SegCs, context->Eip ); + DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", + context->Eax, context->Ebx, context->Ecx, context->Edx, + context->Esi, context->Edi ); + DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", + context->Ebp, context->Esp, context->SegDs, context->SegEs, + context->SegFs, context->SegGs, context->EFlags ); + } + ret = DOSVM_SimulateInt(arg, context, FALSE); + if (TRACE_ON(relay)) { + DPRINTF("Ret DOS int 0x%02x ret=%04lx:%04lx\n", + arg, context->SegCs, context->Eip ); + DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", + context->Eax, context->Ebx, context->Ecx, context->Edx, + context->Esi, context->Edi ); + DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", + context->Ebp, context->Esp, context->SegDs, context->SegEs, + context->SegFs, context->SegGs, context->EFlags ); + } + return ret ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_EXECUTION; + + case EXCEPTION_VM86_STI: + /* case EXCEPTION_VM86_PICRETURN: */ + IF_SET(context); + EnterCriticalSection(&qcrit); + sig_sent++; + while (NtCurrentTeb()->alarms) { + DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL); + /* hmm, instead of relying on this signal counter, we should + * probably check how many ticks have *really* passed, probably using + * QueryPerformanceCounter() or something like that */ + InterlockedDecrement(&(NtCurrentTeb()->alarms)); + } + TRACE_(int)("context=%p, current=%p\n", context, current_context); + TRACE_(int)("cs:ip=%04lx:%04lx, ss:sp=%04lx:%04lx\n", context->SegCs, context->Eip, context->SegSs, context->Esp); + if (!ISV86(context)) { + ERR_(int)("@#&*%%, winedos signal handling is *still* messed up\n"); + } + TRACE_(int)("DOS task enabled interrupts %s events pending, sending events (time=%ld)\n", IS_PEND(context)?"with":"without", GetTickCount()); + DOSVM_SendQueuedEvents(context); + sig_sent=0; + LeaveCriticalSection(&qcrit); + return EXCEPTION_CONTINUE_EXECUTION; + } + return EXCEPTION_CONTINUE_SEARCH; +} + +int WINAPI DOSVM_Enter( CONTEXT86 *context ) +{ + CONTEXT86 *old_context = current_context; + + current_context = context; + __TRY + { + __wine_enter_vm86( context ); + TRACE_(module)( "vm86 returned: %s\n", strerror(errno) ); + } + __EXCEPT(exception_handler) + { + TRACE_(module)( "leaving vm86 mode\n" ); + } + __ENDTRY + current_context = old_context; + return 0; } /*********************************************************************** @@ -572,6 +463,7 @@ void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) LPDOSEVENT event; if ((port==0x20) && (val==0x20)) { + EnterCriticalSection(&qcrit); if (current_event) { /* EOI (End Of Interrupt) */ TRACE("received EOI for current IRQ, clearing\n"); @@ -581,17 +473,16 @@ void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) (*event->relay)(NULL,event->data); free(event); - if (pending_event && - !sig_sent) { + if (pending_event) { /* another event is pending, which we should probably - * be able to process now, so tell dosmod about it */ - TRACE("another event pending, signalling dosmod\n"); - kill(dosmod_pid,SIGUSR2); - sig_sent++; + * be able to process now */ + TRACE("another event pending, setting flag\n"); + current_context->EFlags |= VIP_MASK; } } else { WARN("EOI without active IRQ\n"); } + LeaveCriticalSection(&qcrit); } else { FIXME("unrecognized PIC command %02x\n",val); } @@ -602,25 +493,18 @@ void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) */ void WINAPI DOSVM_SetTimer( UINT ticks ) { - int stat=DOSMOD_SET_TIMER; - struct timeval tim; + struct itimerval tim; - if (write_pipe != -1) { + if (dosvm_pid) { /* the PC clocks ticks at 1193180 Hz */ - tim.tv_sec=0; - tim.tv_usec=MulDiv(ticks,1000000,1193180); + tim.it_interval.tv_sec=0; + tim.it_interval.tv_usec=MulDiv(ticks,1000000,1193180); /* sanity check */ - if (!tim.tv_usec) tim.tv_usec=1; - - if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) { - ERR_(module)("dosmod sync lost, errno=%d\n",errno); - return; - } - if (write(write_pipe,&tim,sizeof(tim))!=sizeof(tim)) { - ERR_(module)("dosmod sync lost, errno=%d\n",errno); - return; - } - /* there's no return */ + if (!tim.it_interval.tv_usec) tim.it_interval.tv_usec=1; + /* first tick value */ + tim.it_value = tim.it_interval; + TRACE_(int)("setting timer tick delay to %ld us\n", tim.it_interval.tv_usec); + setitimer(ITIMER_REAL, &tim, NULL); } } @@ -629,22 +513,11 @@ void WINAPI DOSVM_SetTimer( UINT ticks ) */ UINT WINAPI DOSVM_GetTimer( void ) { - int stat=DOSMOD_GET_TIMER; - struct timeval tim; + struct itimerval tim; - if (write_pipe != -1) { - if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) { - ERR_(module)("dosmod sync lost, errno=%d\n",errno); - return 0; - } - /* read response */ - while (1) { - if (read(read_pipe,&tim,sizeof(tim))==sizeof(tim)) break; - if ((errno==EINTR)||(errno==EAGAIN)) continue; - ERR_(module)("dosmod sync lost, errno=%d\n",errno); - return 0; - } - return MulDiv(tim.tv_usec,1193180,1000000); + if (dosvm_pid) { + getitimer(ITIMER_REAL, &tim); + return MulDiv(tim.it_value.tv_usec,1193180,1000000); } return 0; } diff --git a/dlls/winedos/dosvm.h b/dlls/winedos/dosvm.h new file mode 100644 index 0000000000..10c64fe658 --- /dev/null +++ b/dlls/winedos/dosvm.h @@ -0,0 +1,19 @@ +/* + * DOS virtual machine + * + * Copyright 2000 Ove Kåven + */ + +#ifndef __WINE_DOSVM_H +#define __WINE_DOSVM_H + +#include /* pid_t */ + +typedef struct { + PAPCFUNC proc; + ULONG_PTR arg; +} DOS_SPC; + +extern pid_t dosvm_pid; + +#endif /* __WINE_DOSVM_H */ diff --git a/dlls/winedos/module.c b/dlls/winedos/module.c index 2f50c9c78b..f0b4d9bb6a 100644 --- a/dlls/winedos/module.c +++ b/dlls/winedos/module.c @@ -20,6 +20,8 @@ #include #include "windef.h" #include "wine/winbase16.h" +#include "wingdi.h" +#include "winuser.h" #include "winerror.h" #include "module.h" #include "task.h" @@ -27,7 +29,7 @@ #include "miscemu.h" #include "debugtools.h" #include "dosexe.h" -#include "../../loader/dos/dosmod.h" +#include "dosvm.h" #include "options.h" #include "vga.h" @@ -69,12 +71,11 @@ typedef struct { /* global variables */ -static WORD init_cs,init_ip,init_ss,init_sp; -static char mm_name[128]; +pid_t dosvm_pid; -int read_pipe = -1, write_pipe = -1; -HANDLE hReadPipe, hWritePipe; -pid_t dosmod_pid; +static WORD init_cs,init_ip,init_ss,init_sp; +static HANDLE dosvm_thread, loop_thread; +static DWORD dosvm_tid, loop_tid; static void MZ_Launch(void); static BOOL MZ_InitTask(void); @@ -170,25 +171,10 @@ static WORD MZ_InitEnvironment( LPCSTR env, LPCSTR name ) static BOOL MZ_InitMemory(void) { - int mm_fd; - void *img_base; + /* initialize the memory */ + TRACE("Initializing DOS memory structures\n"); + DOSMEM_Init(TRUE); - /* allocate 1MB+64K shared memory */ - tmpnam(mm_name); - /* strcpy(mm_name,"/tmp/mydosimage"); */ - mm_fd = open(mm_name,O_RDWR|O_CREAT /* |O_TRUNC */,S_IRUSR|S_IWUSR); - if (mm_fd < 0) ERR("file %s could not be opened\n",mm_name); - /* fill the file with the DOS memory */ - if (write( mm_fd, NULL, 0x110000 ) != 0x110000) ERR("cannot write DOS mem\n"); - /* map it in */ - img_base = mmap(NULL,0x110000,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED|MAP_FIXED,mm_fd,0); - close( mm_fd ); - - if (img_base) - { - ERR("could not map shared memory, error=%s\n",strerror(errno)); - return FALSE; - } MZ_InitHandlers(); return TRUE; } @@ -307,7 +293,6 @@ static BOOL MZ_DoLoadImage( HANDLE hFile, LPCSTR filename, OverlayBlock *oblk ) } if (alloc && !MZ_InitTask()) { - MZ_KillTask(); SetLastError(ERROR_GEN_FAILURE); return FALSE; } @@ -316,9 +301,6 @@ static BOOL MZ_DoLoadImage( HANDLE hFile, LPCSTR filename, OverlayBlock *oblk ) load_error: DOSVM_psp = oldpsp_seg; - if (alloc) { - if (mm_name[0]!=0) unlink(mm_name); - } return FALSE; } @@ -328,7 +310,7 @@ load_error: */ void WINAPI MZ_LoadImage( LPCSTR filename, HANDLE hFile ) { - if (MZ_DoLoadImage( hFile, filename, NULL )) MZ_Launch(); + if (MZ_DoLoadImage( hFile, filename, NULL )) MZ_Launch(); } /*********************************************************************** @@ -400,8 +382,8 @@ BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID para */ void WINAPI MZ_AllocDPMITask( void ) { - MZ_InitMemory(); - MZ_InitTask(); + MZ_InitMemory(); + MZ_InitTask(); } /*********************************************************************** @@ -409,122 +391,26 @@ void WINAPI MZ_AllocDPMITask( void ) */ void WINAPI MZ_RunInThread( PAPCFUNC proc, ULONG_PTR arg ) { - proc(arg); + if (loop_thread) { + DOS_SPC spc; + HANDLE event; + + spc.proc = proc; + spc.arg = arg; + event = CreateEventA(NULL, TRUE, FALSE, NULL); + PostThreadMessageA(loop_tid, WM_USER, event, (LPARAM)&spc); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } else + proc(arg); } -static void MZ_InitTimer( int ver ) -{ - if (ver<1) { - /* can't make timer ticks */ - } else { - int func; - struct timeval tim; - - /* start dosmod timer at 55ms (18.2Hz) */ - func=DOSMOD_SET_TIMER; - tim.tv_sec=0; tim.tv_usec=54925; - write(write_pipe,&func,sizeof(func)); - write(write_pipe,&tim,sizeof(tim)); - } -} - -static BOOL MZ_InitTask(void) -{ - int write_fd[2],x_fd; - pid_t child; - char path[256],*fpath; - - /* create pipes */ - if (!CreatePipe(&hReadPipe,&hWritePipe,NULL,0)) return FALSE; - if (pipe(write_fd)<0) { - CloseHandle(hReadPipe); - CloseHandle(hWritePipe); - return FALSE; - } - - read_pipe = FILE_GetUnixHandle( hReadPipe, GENERIC_READ ); - x_fd = FILE_GetUnixHandle( hWritePipe, GENERIC_WRITE ); - - TRACE("win32 pipe: read=%d, write=%d, unix pipe: read=%d, write=%d\n", - hReadPipe,hWritePipe,read_pipe,x_fd); - TRACE("outbound unix pipe: read=%d, write=%d, pid=%d\n",write_fd[0],write_fd[1],getpid()); - - write_pipe=write_fd[1]; - - TRACE("Loading DOS VM support module\n"); - if ((child=fork())<0) { - close(write_fd[0]); - close(read_pipe); - close(write_pipe); - close(x_fd); - CloseHandle(hReadPipe); - CloseHandle(hWritePipe); - return FALSE; - } - if (child!=0) { - /* parent process */ - int ret; - - close(write_fd[0]); - close(x_fd); - dosmod_pid = child; - /* wait for child process to signal readiness */ - while (1) { - if (read(read_pipe,&ret,sizeof(ret))==sizeof(ret)) break; - if ((errno==EINTR)||(errno==EAGAIN)) continue; - /* failure */ - ERR("dosmod has failed to initialize\n"); - if (mm_name[0]!=0) unlink(mm_name); - return FALSE; - } - /* the child has now mmaped the temp file, it's now safe to unlink. - * do it here to avoid leaving a mess in /tmp if/when Wine crashes... */ - if (mm_name[0]!=0) unlink(mm_name); - /* start simulated system timer */ - MZ_InitTimer(ret); - if (ret<2) { - ERR("dosmod version too old! Please install newer dosmod properly\n"); - ERR("If you don't, the new dosmod event handling system will not work\n"); - } - /* all systems are now go */ - } else { - /* child process */ - close(read_pipe); - close(write_pipe); - /* put our pipes somewhere dosmod can find them */ - dup2(write_fd[0],0); /* stdin */ - dup2(x_fd,1); /* stdout */ - /* now load dosmod */ - /* check argv[0]-derived paths first, since the newest dosmod is most likely there - * (at least it was once for Andreas Mohr, so I decided to make it easier for him) */ - fpath=strrchr(strcpy(path,full_argv0),'/'); - if (fpath) { - strcpy(fpath,"/dosmod"); - execl(path,mm_name,NULL); - strcpy(fpath,"/loader/dos/dosmod"); - execl(path,mm_name,NULL); - } - /* okay, it wasn't there, try in the path */ - execlp("dosmod",mm_name,NULL); - /* last desperate attempts: current directory */ - execl("dosmod",mm_name,NULL); - /* and, just for completeness... */ - execl("loader/dos/dosmod",mm_name,NULL); - /* if failure, exit */ - ERR("Failed to spawn dosmod, error=%s\n",strerror(errno)); - exit(1); - } - return TRUE; -} - -static void MZ_Launch(void) +static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra ) { CONTEXT context; - TDB *pTask = GlobalLock16( GetCurrentTask() ); - BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); + DWORD ret; - MZ_FillPSP(psp_start, GetCommandLineA()); - pTask->flags |= TDBF_WINOLDAP; + dosvm_pid = getpid(); memset( &context, 0, sizeof(context) ); context.SegCs = init_cs; @@ -534,15 +420,54 @@ static void MZ_Launch(void) context.SegDs = DOSVM_psp; context.SegEs = DOSVM_psp; context.EFlags = 0x00080000; /* virtual interrupt flag */ + DOSVM_SetTimer(0x10000); + ret = DOSVM_Enter( &context ); + + dosvm_pid = 0; + return ret; +} + +static BOOL MZ_InitTask(void) +{ + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &loop_thread, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + return FALSE; + dosvm_thread = CreateThread(NULL, 0, MZ_DOSVM, NULL, CREATE_SUSPENDED, &dosvm_tid); + if (!dosvm_thread) { + CloseHandle(loop_thread); + loop_thread = 0; + return FALSE; + } + loop_tid = GetCurrentThreadId(); + return TRUE; +} + +static void MZ_Launch(void) +{ + TDB *pTask = TASK_GetCurrent(); + BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); + + MZ_FillPSP(psp_start, GetCommandLineA()); + pTask->flags |= TDBF_WINOLDAP; + _LeaveWin16Lock(); - DOSVM_Enter( &context ); + + ResumeThread(dosvm_thread); + DOSVM_Loop(NULL); + ExitThread(0); } static void MZ_KillTask(void) { TRACE("killing DOS task\n"); VGA_Clean(); - kill(dosmod_pid,SIGTERM); + PostThreadMessageA(loop_tid, WM_QUIT, 0, 0); + WaitForSingleObject(loop_thread, INFINITE); /* ? */ + CloseHandle(dosvm_thread); + dosvm_thread = 0; dosvm_tid = 0; + CloseHandle(loop_thread); + loop_thread = 0; loop_tid = 0; } /*********************************************************************** @@ -590,7 +515,7 @@ void WINAPI MZ_Exit( CONTEXT86 *context, BOOL cs_psp, WORD retval ) */ BOOL WINAPI MZ_Current( void ) { - return (write_pipe != -1); /* FIXME: do a better check */ + return (dosvm_pid != 0); /* FIXME: do a better check */ } #else /* !MZ_SUPPORTED */