diff --git a/include/dosexe.h b/include/dosexe.h index 2b317a07356f0f556de0c9e273f48f198cc94378..7d126c7a2c2e275ba2e2e091080a6a427a4f2ec6 100644 --- a/include/dosexe.h +++ b/include/dosexe.h @@ -9,8 +9,17 @@ #include <sys/types.h> /* pid_t */ #include "winbase.h" /* for LPSTARTUPINFO32A */ +#include "winnt.h" /* for PCONTEXT */ #include "sig_context.h" +typedef struct _DOSSYSTEM { + int id; + void *data; + struct _DOSSYSTEM *next; +} DOSSYSTEM; + +struct _DOSEVENT; + typedef struct _DOSTASK { LPVOID img; unsigned img_ofs; @@ -18,14 +27,30 @@ typedef struct _DOSTASK { WORD init_cs,init_ip,init_ss,init_sp; WORD xms_seg; WORD dpmi_seg,dpmi_sel,dpmi_flag; - WORD system_timer; HMODULE16 hModule; char mm_name[128]; int mm_fd; + HANDLE hReadPipe,hXPipe; int read_pipe,write_pipe; pid_t task; + int sig_sent; + struct _DOSEVENT *pending,*current; + DOSSYSTEM *sys; } DOSTASK, *LPDOSTASK; +typedef struct _DOSEVENT { + int irq,priority; + void (*relay)(LPDOSTASK,PCONTEXT,void*); + void *data; + struct _DOSEVENT *next; +} DOSEVENT, *LPDOSEVENT; + +#define DOS_PRIORITY_REALTIME 0 /* IRQ0 */ +#define DOS_PRIORITY_KEYBOARD 1 /* IRQ1 */ +#define DOS_PRIORITY_VGA 2 /* IRQ9 */ +#define DOS_PRIORITY_MOUSE 5 /* IRQ12 */ +#define DOS_PRIORITY_SERIAL 10 /* IRQ4 */ + #if defined(linux) && defined(__i386__) #define MZ_SUPPORTED @@ -33,19 +58,21 @@ typedef struct _DOSTASK { extern BOOL MZ_InitTask( LPDOSTASK lpDosTask ); extern void MZ_KillModule( LPDOSTASK lpDosTask ); extern LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule ); +extern void DOSVM_QueueEvent( int irq, int priority, void (*relay)(LPDOSTASK,PCONTEXT,void*), void *data ); #endif /* linux-i386 */ #define V86_FLAG 0x00020000 -extern void MZ_Tick( WORD handle ); - extern BOOL MZ_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmdline, LPCSTR env, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, LPSTARTUPINFOA startup, LPPROCESS_INFORMATION info ); extern int DOSVM_Enter( PCONTEXT context ); +extern void DOSVM_PIC_ioport_out( WORD port, BYTE val ); extern void DOSVM_SetTimer( unsigned ticks ); extern unsigned DOSVM_GetTimer( void ); +extern void DOSVM_SetSystemData( int id, void *data ); +extern void* DOSVM_GetSystemData( int id ); #endif /* __WINE_DOSEXE_H */ diff --git a/include/winbase.h b/include/winbase.h index 5bdb71f47d67f887755d5a0acd7fd87c9484ca08..74a28c709d2d94788148980339eaa722db10e874 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1354,6 +1354,7 @@ HANDLE WINAPI CreateFileMappingW(HANDLE,LPSECURITY_ATTRIBUTES,DWORD, HANDLE WINAPI CreateMutexA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR); HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR); #define CreateMutex WINELIB_NAME_AW(CreateMutex) +BOOL WINAPI CreatePipe(PHANDLE,PHANDLE,LPSECURITY_ATTRIBUTES,DWORD); BOOL WINAPI CreateProcessA(LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,BOOL,DWORD,LPVOID,LPCSTR, LPSTARTUPINFOA,LPPROCESS_INFORMATION); diff --git a/loader/dos/dosvm.c b/loader/dos/dosvm.c index ce93852dfb92029145688ccc5bb65f4bba879137..2648019ca09c8c4c50dea0a404df00a96ebee8bf 100644 --- a/loader/dos/dosvm.c +++ b/loader/dos/dosvm.c @@ -18,6 +18,7 @@ #include <sys/stat.h> #include "wine/winbase16.h" +#include "winuser.h" #include "winnt.h" #include "sig_context.h" #include "msdos.h" @@ -36,6 +37,14 @@ #include <sys/mman.h> #include <sys/vm86.h> +#define IF_CLR(ctx) EFL_reg(ctx) &= ~VIF_MASK +#define IF_ENABLED(ctx) (EFL_reg(ctx) & VIF_MASK) +#define SET_PEND(ctx) EFL_reg(ctx) |= VIP_MASK +#define CLR_PEND(ctx) EFL_reg(ctx) &= ~VIP_MASK +#define IS_PEND(ctx) (EFL_reg(ctx) & VIP_MASK) + +#undef TRY_PICRETURN + static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn, int sig, struct vm86plus_struct*VM86 ) { @@ -90,15 +99,104 @@ static int DOSVM_Int( int vect, PCONTEXT context, LPDOSTASK lpDosTask ) static void DOSVM_SimulateInt( int vect, PCONTEXT context, LPDOSTASK lpDosTask ) { - FARPROC16 handler=INT_GetRMHandler(vect); - WORD*stack=(WORD*)(V86BASE(context)+(((DWORD)SS_reg(context))<<4)+SP_reg(context)); - - *(--stack)=FL_reg(context); - *(--stack)=CS_reg(context); - *(--stack)=IP_reg(context); - SP_reg(context)-=6; - CS_reg(context)=SELECTOROF(handler); - IP_reg(context)=OFFSETOF(handler); + FARPROC16 handler=INT_GetRMHandler(vect); + + if (SELECTOROF(handler)==0xf000) { + /* if internal interrupt, call it directly */ + INT_RealModeInterrupt(vect,context); + } else { + WORD*stack=(WORD*)(V86BASE(context)+(((DWORD)SS_reg(context))<<4)+SP_reg(context)); + WORD flag=FL_reg(context); + + if (IF_ENABLED(context)) flag|=IF_MASK; + else flag&=~IF_MASK; + + *(--stack)=flag; + *(--stack)=CS_reg(context); + *(--stack)=IP_reg(context); + SP_reg(context)-=6; + CS_reg(context)=SELECTOROF(handler); + IP_reg(context)=OFFSETOF(handler); + IF_CLR(context); + } +} + +#define SHOULD_PEND(x) \ + (x && ((!lpDosTask->current) || (x->priority < lpDosTask->current->priority))) + +static void DOSVM_SendQueuedEvent(PCONTEXT context, LPDOSTASK lpDosTask) +{ + LPDOSEVENT event = lpDosTask->pending; + + if (SHOULD_PEND(event)) { + /* remove from "pending" list */ + lpDosTask->pending = event->next; + /* process event */ + if (event->irq>=0) { + /* it's an IRQ, move it to "current" list */ + event->next = lpDosTask->current; + lpDosTask->current = event; + TRACE(int,"dispatching IRQ %d\n",event->irq); + /* note that if DOSVM_SimulateInt calls an internal interrupt directly, + * lpDosTask->current might be cleared (and event freed) in this very call! */ + DOSVM_SimulateInt((event->irq<8)?(event->irq+8):(event->irq-8+0x70),context,lpDosTask); + } else { + /* callback event */ + TRACE(int,"dispatching callback event\n"); + (*event->relay)(lpDosTask,context,event->data); + free(event); + } + } + if (!SHOULD_PEND(lpDosTask->pending)) { + TRACE(int,"clearing Pending flag\n"); + CLR_PEND(context); + } +} + +static void DOSVM_SendQueuedEvents(PCONTEXT context, LPDOSTASK lpDosTask) +{ + /* we will send all queued events as long as interrupts are enabled, + * but IRQ events will disable interrupts again */ + while (IS_PEND(context) && IF_ENABLED(context)) + DOSVM_SendQueuedEvent(context,lpDosTask); +} + +void DOSVM_QueueEvent( int irq, int priority, void (*relay)(LPDOSTASK,PCONTEXT,void*), void *data) +{ + TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + LPDOSEVENT event, cur, prev; + + GlobalUnlock16( GetCurrentTask() ); + if (pModule && pModule->lpDosTask) { + event = malloc(sizeof(DOSEVENT)); + if (!event) { + ERR(int,"out of memory allocating event entry\n"); + return; + } + event->irq = irq; event->priority = priority; + event->relay = relay; event->data = data; + + /* insert event into linked list, in order *after* + * all earlier events of higher or equal priority */ + cur = pModule->lpDosTask->pending; prev = NULL; + while (cur && cur->priority<=priority) { + prev = cur; + cur = cur->next; + } + event->next = cur; + if (prev) prev->next = event; + else pModule->lpDosTask->pending = event; + + /* get dosmod's attention to the new event, except for irq==0 where we already have it */ + if (irq && !pModule->lpDosTask->sig_sent) { + TRACE(int,"new event queued, signalling dosmod\n"); + kill(pModule->lpDosTask->task,SIGUSR2); + pModule->lpDosTask->sig_sent++; + } else { + TRACE(int,"new event queued\n"); + } + } } #define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \ @@ -130,12 +228,34 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, int sig, CV; #undef CP (void*)V86BASE(&context)=lpDosTask->img; +#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(lpDosTask->pending)) { + SET_PEND(&context); + } +#endif switch (VM86_TYPE(fn)) { case VM86_SIGNAL: TRACE(int,"DOS module caught signal %d\n",sig); - if (sig==SIGALRM) { - DOSVM_SimulateInt(8,&context,lpDosTask); + if ((sig==SIGALRM) || (sig==SIGUSR2)) { + if (sig==SIGALRM) { + DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL); + } + if (lpDosTask->pending) { + TRACE(int,"setting Pending flag, interrupts are currently %s\n", + IF_ENABLED(&context) ? "enabled" : "disabled"); + SET_PEND(&context); + DOSVM_SendQueuedEvents(&context,lpDosTask); + } else { + TRACE(int,"no events are pending, clearing Pending flag\n"); + CLR_PEND(&context); + } + if (sig==SIGUSR2) lpDosTask->sig_sent--; } else if (sig==SIGHUP) { if (ctx_debug_call) ctx_debug_call(SIGTRAP,&context); @@ -159,9 +279,10 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, int sig, 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: - break; case VM86_PICRETURN: - printf("Trapped due to pending PIC request\n"); break; + TRACE(int,"DOS task enabled interrupts with events pending, sending events\n"); + DOSVM_SendQueuedEvents(&context,lpDosTask); + break; case VM86_TRAP: if (ctx_debug_call) ctx_debug_call(SIGTRAP,&context); break; @@ -173,9 +294,42 @@ static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, int sig, #define CP(x,y) VM86->regs.x = y##_reg(&context) CV; #undef CP +#ifdef TRY_PICRETURN + VM86->vm86plus.force_return_for_pic = IS_PEND(&context) ? 1 : 0; + CLR_PEND(&context); +#endif return ret; } +void DOSVM_ProcessMessage(LPDOSTASK lpDosTask,MSG *msg) +{ + BYTE scan = 0; + + fprintf(stderr,"got message %04x, wparam=%08x, lparam=%08lx\n",msg->message,msg->wParam,msg->lParam); + if ((msg->message>=WM_MOUSEFIRST)&& + (msg->message<=WM_MOUSELAST)) { + INT_Int33Message(msg->message,msg->wParam,msg->lParam); + } else { + switch (msg->message) { + case WM_KEYUP: + scan = 0x80; + case WM_KEYDOWN: + scan |= (msg->lParam >> 16) & 0x7f; + + /* check whether extended bit is set, + * and if so, queue the extension prefix */ + if (msg->lParam & 0x1000000) { + /* FIXME: some keys (function keys) have + * extended bit set even when they shouldn't, + * should check for them */ + INT_Int09SendScan(0xE0); + } + INT_Int09SendScan(scan); + break; + } + } +} + int DOSVM_Enter( PCONTEXT context ) { TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); @@ -183,7 +337,10 @@ int DOSVM_Enter( PCONTEXT context ) LPDOSTASK lpDosTask; struct vm86plus_struct VM86; int stat,len,sig; - fd_set readfds,exceptfds; + DWORD waitret; + MSG msg; + fd_set readfds; + struct timeval timeout={0,0}; GlobalUnlock16( GetCurrentTask() ); if (!pModule) { @@ -212,6 +369,7 @@ int DOSVM_Enter( PCONTEXT context ) VM86.regs.esp=lpDosTask->init_sp; VM86.regs.ds=lpDosTask->psp_seg; VM86.regs.es=lpDosTask->psp_seg; + VM86.regs.eflags=VIF_MASK; /* hmm, what else do we need? */ } @@ -221,57 +379,62 @@ int DOSVM_Enter( PCONTEXT context ) errno = 0; /* transmit VM86 structure to dosmod task */ if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) { - ERR(module,"dosmod sync lost, errno=%d\n",errno); + ERR(module,"dosmod sync lost, errno=%d, fd=%d, pid=%d\n",errno,lpDosTask->write_pipe,getpid()); return -1; } if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) { ERR(module,"dosmod sync lost, errno=%d\n",errno); return -1; } - /* wait for response, with async events enabled */ - FD_ZERO(&readfds); - FD_ZERO(&exceptfds); - SIGNAL_MaskAsyncEvents(FALSE); - do { - FD_SET(lpDosTask->read_pipe,&readfds); - FD_SET(lpDosTask->read_pipe,&exceptfds); - select(lpDosTask->read_pipe+1,&readfds,NULL,&exceptfds,NULL); - } while (!(FD_ISSET(lpDosTask->read_pipe,&readfds)|| - FD_ISSET(lpDosTask->read_pipe,&exceptfds))); - SIGNAL_MaskAsyncEvents(TRUE); - /* read response (with async events disabled to avoid some strange problems) */ do { - if ((len=read(lpDosTask->read_pipe,&stat,sizeof(stat)))!=sizeof(stat)) { + /* check for messages (waste time before the response check below) */ + while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) { + /* got a message */ + DOSVM_ProcessMessage(lpDosTask,&msg); + /* we don't need a TranslateMessage here */ + DispatchMessageA(&msg); + } + /* quick check for response from dosmod + * (faster than doing the full blocking wait, if data already available) */ + FD_ZERO(&readfds); FD_SET(lpDosTask->read_pipe,&readfds); + if (select(lpDosTask->read_pipe+1,&readfds,NULL,NULL,&timeout)>0) + break; + /* nothing yet, block while waiting for something to do */ + waitret=MsgWaitForMultipleObjects(1,&(lpDosTask->hReadPipe),FALSE,INFINITE,QS_ALLINPUT); + if (waitret==(DWORD)-1) { + ERR(module,"dosvm wait error=%ld\n",GetLastError()); + } + } while (waitret!=WAIT_OBJECT_0); + /* read response */ + while (1) { + if ((len=read(lpDosTask->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; } ERR(module,"dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len); return -1; - } - } while (0); + } TRACE(module,"dosmod return code=%d\n",stat); - do { - if ((len=read(lpDosTask->read_pipe,&VM86,sizeof(VM86)))!=sizeof(VM86)) { + while (1) { + if ((len=read(lpDosTask->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; - } - } while (0); + } if ((stat&0xff)==DOSMOD_SIGNAL) { - do { - if ((len=read(lpDosTask->read_pipe,&sig,sizeof(sig)))!=sizeof(sig)) { - if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) { - WARN(module,"rereading dosmod signal due to errno=%d, result=%d\n",errno,len); - continue; - } - ERR(module,"dosmod sync lost reading signal, errno=%d, result=%d\n",errno,len); - return -1; - } - } while (0); + while (1) { + if ((len=read(lpDosTask->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; + } + 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(lpDosTask,stat,sig,&VM86)>=0); @@ -284,6 +447,41 @@ int DOSVM_Enter( PCONTEXT context ) return 0; } +void DOSVM_PIC_ioport_out( WORD port, BYTE val) +{ + TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + LPDOSEVENT event; + + GlobalUnlock16( GetCurrentTask() ); + if (pModule && pModule->lpDosTask) { + if ((port==0x20) && (val==0x20)) { + if (pModule->lpDosTask->current) { + /* EOI (End Of Interrupt) */ + TRACE(int,"received EOI for current IRQ, clearing\n"); + event = pModule->lpDosTask->current; + pModule->lpDosTask->current = event->next; + if (event->relay) + (*event->relay)(pModule->lpDosTask,NULL,event->data); + free(event); + + if (pModule->lpDosTask->pending && + !pModule->lpDosTask->sig_sent) { + /* another event is pending, which we should probably + * be able to process now, so tell dosmod about it */ + TRACE(int,"another event pending, signalling dosmod\n"); + kill(pModule->lpDosTask->task,SIGUSR2); + pModule->lpDosTask->sig_sent++; + } + } else { + WARN(int,"EOI without active IRQ\n"); + } + } else { + FIXME(int,"unrecognized PIC command %02x\n",val); + } + } +} + void DOSVM_SetTimer( unsigned ticks ) { TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); @@ -334,19 +532,49 @@ unsigned DOSVM_GetTimer( void ) return 0; } -void MZ_Tick( WORD handle ) +void DOSVM_SetSystemData( int id, void *data ) { - /* find the DOS task that has the right system_timer handle... */ - /* should usually be the current, so let's just be lazy... */ - TDB *pTask = (TDB*)GlobalLock16( GetCurrentTask() ); - NE_MODULE *pModule = pTask ? NE_GetPtr( pTask->hModule ) : NULL; - LPDOSTASK lpDosTask = pModule ? pModule->lpDosTask : NULL; + TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + DOSSYSTEM *sys, *prev; + + GlobalUnlock16( GetCurrentTask() ); + if (pModule && pModule->lpDosTask) { + sys = pModule->lpDosTask->sys; + prev = NULL; + while (sys && (sys->id != id)) { + prev = sys; + sys = sys->next; + } + if (sys) { + free(sys->data); + sys->data = data; + } else { + sys = malloc(sizeof(DOSSYSTEM)); + sys->id = id; + sys->data = data; + sys->next = NULL; + if (prev) prev->next = sys; + else pModule->lpDosTask->sys = sys; + } + } else free(data); +} - GlobalUnlock16( GetCurrentTask() ); - if (lpDosTask&&(lpDosTask->system_timer==handle)) { - /* BIOS timer tick */ - (*((DWORD*)(((BYTE*)(lpDosTask->img))+0x46c)))++; - } +void* DOSVM_GetSystemData( int id ) +{ + TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() ); + NE_MODULE *pModule = NE_GetPtr( pTask->hModule ); + DOSSYSTEM *sys; + + GlobalUnlock16( GetCurrentTask() ); + if (pModule && pModule->lpDosTask) { + sys = pModule->lpDosTask->sys; + while (sys && (sys->id != id)) + sys = sys->next; + if (sys) + return sys->data; + } + return NULL; } #else /* !MZ_SUPPORTED */ @@ -357,8 +585,10 @@ int DOSVM_Enter( PCONTEXT context ) return -1; } -void MZ_Tick( WORD handle ) {} +void DOSVM_PIC_ioport_out( WORD port, BYTE val) {} void DOSVM_SetTimer( unsigned ticks ) {} unsigned DOSVM_GetTimer( void ) { return 0; } +void DOSVM_SetSystemData( int id, void *data ) { free(data); } +void* DOSVM_GetSystemData( int id ) { return NULL; } #endif diff --git a/loader/dos/module.c b/loader/dos/module.c index 9a8b301d0b276fbe75c7d451fffe1a010a62a965..2ac543c2e0018505d3eb2b969e2de4c17a34e491 100644 --- a/loader/dos/module.c +++ b/loader/dos/module.c @@ -32,6 +32,7 @@ #include "dosexe.h" #include "dosmod.h" #include "options.h" +#include "server.h" #ifdef MZ_SUPPORTED @@ -322,11 +323,7 @@ LPDOSTASK MZ_AllocDPMITask( HMODULE16 hModule ) static void MZ_InitTimer( LPDOSTASK lpDosTask, int ver ) { if (ver<1) { -#if 0 - /* start simulated system 55Hz timer */ - lpDosTask->system_timer = CreateSystemTimer( 55, MZ_Tick ); - TRACE(module,"created 55Hz timer tick, handle=%d\n",lpDosTask->system_timer); -#endif + /* can't make timer ticks */ } else { int func; struct timeval tim; @@ -341,18 +338,36 @@ static void MZ_InitTimer( LPDOSTASK lpDosTask, int ver ) BOOL MZ_InitTask( LPDOSTASK lpDosTask ) { - int read_fd[2],write_fd[2]; - pid_t child; - char *fname,*farg,arg[16],fproc[64],path[256],*fpath; - - if (!lpDosTask) return FALSE; - /* create read pipe */ - if (pipe(read_fd)<0) return FALSE; - if (pipe(write_fd)<0) { - close(read_fd[0]); close(read_fd[1]); return FALSE; - } - lpDosTask->read_pipe=read_fd[0]; - lpDosTask->write_pipe=write_fd[1]; + int write_fd[2],x_fd; + pid_t child; + char *fname,*farg,arg[16],fproc[64],path[256],*fpath; + SECURITY_ATTRIBUTES attr={sizeof(attr),NULL,TRUE}; + struct get_read_fd_request r_req; + struct get_write_fd_request w_req; + + if (!lpDosTask) return FALSE; + /* create pipes */ + /* this happens in the wrong process context, so we have to let the new process + inherit it... (FIXME: call MZ_InitTask in the right process context) */ + if (!CreatePipe(&(lpDosTask->hReadPipe),&(lpDosTask->hXPipe),&attr,0)) return FALSE; + if (pipe(write_fd)<0) { + CloseHandle(lpDosTask->hReadPipe); + CloseHandle(lpDosTask->hXPipe); + return FALSE; + } + r_req.handle = lpDosTask->hReadPipe; + CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &r_req, sizeof(r_req) ); + CLIENT_WaitReply( NULL, &(lpDosTask->read_pipe), 0 ); + w_req.handle = lpDosTask->hXPipe; + CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &w_req, sizeof(w_req) ); + CLIENT_WaitReply( NULL, &x_fd, 0 ); + + TRACE(module,"win32 pipe: read=%d, write=%d, unix pipe: read=%d, write=%d\n", + lpDosTask->hReadPipe,lpDosTask->hXPipe,lpDosTask->read_pipe,x_fd); + TRACE(module,"outbound unix pipe: read=%d, write=%d, pid=%d\n",write_fd[0],write_fd[1],getpid()); + + lpDosTask->write_pipe=write_fd[1]; + /* if we have a mapping file, use it */ fname=lpDosTask->mm_name; farg=NULL; if (!fname[0]) { @@ -362,16 +377,22 @@ BOOL MZ_InitTask( LPDOSTASK lpDosTask ) fname=fproc; farg=arg; } - TRACE(module,"Loading DOS VM support module (hmodule=%04x)\n",lpDosTask->hModule); - if ((child=fork())<0) { - close(write_fd[0]); close(write_fd[1]); - close(read_fd[0]); close(read_fd[1]); return FALSE; - } + TRACE(module,"Loading DOS VM support module (hmodule=%04x)\n",lpDosTask->hModule); + if ((child=fork())<0) { + close(write_fd[0]); + close(lpDosTask->read_pipe); + close(lpDosTask->write_pipe); + close(x_fd); + CloseHandle(lpDosTask->hReadPipe); + CloseHandle(lpDosTask->hXPipe); + return FALSE; + } if (child!=0) { /* parent process */ int ret; - close(read_fd[1]); close(write_fd[0]); + close(write_fd[0]); + close(x_fd); lpDosTask->task=child; /* wait for child process to signal readiness */ do { @@ -388,26 +409,36 @@ BOOL MZ_InitTask( LPDOSTASK lpDosTask ) if (lpDosTask->mm_name[0]!=0) unlink(lpDosTask->mm_name); /* start simulated system timer */ MZ_InitTimer(lpDosTask,ret); + if (ret<2) { + ERR(module,"dosmod version too old! Please install newer dosmod properly\n"); + ERR(module,"If you don't, the new dosmod event handling system will not work\n"); + } /* all systems are now go */ } else { /* child process */ - close(read_fd[0]); close(write_fd[1]); + close(lpDosTask->read_pipe); + close(lpDosTask->write_pipe); /* put our pipes somewhere dosmod can find them */ - dup2(write_fd[0],0); /* stdin */ - dup2(read_fd[1],1); /* stdout */ + dup2(write_fd[0],0); /* stdin */ + dup2(x_fd,1); /* stdout */ /* enable signals */ SIGNAL_MaskAsyncEvents(FALSE); /* now load dosmod */ - execlp("dosmod",fname,farg,NULL); - execl("dosmod",fname,farg,NULL); - /* hmm, they didn't install properly */ - execl("loader/dos/dosmod",fname,farg,NULL); - /* last resort, try to find it through argv[0] */ + /* 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,Options.argv0),'/'); if (fpath) { + strcpy(fpath,"/dosmod"); + execl(path,fname,farg,NULL); strcpy(fpath,"/loader/dos/dosmod"); execl(path,fname,farg,NULL); } + /* okay, it wasn't there, try in the path */ + execlp("dosmod",fname,farg,NULL); + /* last desperate attempts: current directory */ + execl("dosmod",fname,farg,NULL); + /* and, just for completeness... */ + execl("loader/dos/dosmod",fname,farg,NULL); /* if failure, exit */ ERR(module,"Failed to spawn dosmod, error=%s\n",strerror(errno)); exit(1); @@ -464,6 +495,7 @@ BOOL MZ_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmdline, LPCSTR env, SetLastError(ERROR_GEN_FAILURE); return FALSE; } + inherit = TRUE; /* bad hack for inheriting the CreatePipe... */ if (!PROCESS_Create( pModule, cmdline, env, 0, 0, psa, tsa, inherit, startup, info )) return FALSE; @@ -473,17 +505,33 @@ BOOL MZ_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmdline, LPCSTR env, void MZ_KillModule( LPDOSTASK lpDosTask ) { - TRACE(module,"killing DOS task\n"); -#if 0 - SYSTEM_KillSystemTimer(lpDosTask->system_timer); -#endif - if (lpDosTask->mm_name[0]!=0) { - munmap(lpDosTask->img,0x110000-START_OFFSET); - close(lpDosTask->mm_fd); - } else VirtualFree(lpDosTask->img,0x110000,MEM_RELEASE); - close(lpDosTask->read_pipe); - close(lpDosTask->write_pipe); - kill(lpDosTask->task,SIGTERM); + DOSEVENT *event,*p_event; + DOSSYSTEM *sys,*p_sys; + + TRACE(module,"killing DOS task\n"); + if (lpDosTask->mm_name[0]!=0) { + munmap(lpDosTask->img,0x110000-START_OFFSET); + close(lpDosTask->mm_fd); + } else VirtualFree(lpDosTask->img,0x110000,MEM_RELEASE); + close(lpDosTask->read_pipe); + close(lpDosTask->write_pipe); + CloseHandle(lpDosTask->hReadPipe); + CloseHandle(lpDosTask->hXPipe); + kill(lpDosTask->task,SIGTERM); +/* free memory allocated for events and systems */ +#define DFREE(var,pvar,svar) \ + var = lpDosTask->svar; \ + while (var) { \ + if (var->data) free(var->data); \ + pvar = var->next; free(var); var = pvar; \ + } + + DFREE(event,p_event,pending) + DFREE(event,p_event,current) + DFREE(sys,p_sys,sys) + +#undef DFREE + #if 0 /* FIXME: this seems to crash */ if (lpDosTask->dpmi_sel)