From a814c4ef0843a9a702c3c58edf7cd2f2488a1b1c Mon Sep 17 00:00:00 2001
From: Ove Kaaven <ovek@arcticnet.no>
Date: Sun, 6 Jan 2002 18:34:02 +0000
Subject: [PATCH] DOS support restructure. The DOS virtual machine is now a set
 of threads running within Wine's own address space, obsoleting the old dosmod
 module.

---
 dlls/winedos/dosvm.c  | 413 +++++++++++++++---------------------------
 dlls/winedos/dosvm.h  |  19 ++
 dlls/winedos/module.c | 207 +++++++--------------
 3 files changed, 228 insertions(+), 411 deletions(-)
 create mode 100644 dlls/winedos/dosvm.h

diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c
index f8338b9c2b0..a8a439c4926 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;
-
- 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;
+  HANDLE obj = GetStdHandle(STD_INPUT_HANDLE);
+  MSG msg;
+  DWORD waitret;
+
+  for(;;) {
+    TRACE_(int)("waiting for action\n");
+    waitret = MsgWaitForMultipleObjects(1, &obj, FALSE, INFINITE, QS_ALLINPUT);
+    if (waitret == WAIT_OBJECT_0) {
+      DOSVM_ProcessConsole();
+    }
+    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;
+	}
+      }
+    }
+    else break;
   }
-  /* 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;
+  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));
     }
-    ERR_(module)("dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len);
-    return -1;
+    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;
   }
-  TRACE_(module)("dosmod return code=%d\n",stat);
-  if (stat==DOSMOD_LEFTIDLE) {
-    continue;
+  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) );
   }
-  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;
+  __EXCEPT(exception_handler)
+  {
+    TRACE_(module)( "leaving vm86 mode\n" );
   }
-  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;
-      }
-      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--;
-
-#define CP(x,y) context->y = VM86.regs.x
-  CV;
-#undef CP
- return 0;
+  __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 00000000000..10c64fe658f
--- /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 <sys/types.h> /* 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 2f50c9c78b4..f0b4d9bb6a8 100644
--- a/dlls/winedos/module.c
+++ b/dlls/winedos/module.c
@@ -20,6 +20,8 @@
 #include <sys/time.h>
 #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;
-
-    /* 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;
-    }
+    /* initialize the memory */
+    TRACE("Initializing DOS memory structures\n");
+    DOSMEM_Init(TRUE);
+
     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,140 +391,83 @@ 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 )
+static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra )
 {
- 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;
-  }
+  CONTEXT context;
+  DWORD ret;
 
-  read_pipe = FILE_GetUnixHandle( hReadPipe, GENERIC_READ );
-  x_fd = FILE_GetUnixHandle( hWritePipe, GENERIC_WRITE );
+  dosvm_pid = getpid();
 
-  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());
+  memset( &context, 0, sizeof(context) );
+  context.SegCs  = init_cs;
+  context.Eip    = init_ip;
+  context.SegSs  = init_ss;
+  context.Esp    = init_sp;
+  context.SegDs  = DOSVM_psp;
+  context.SegEs  = DOSVM_psp;
+  context.EFlags = 0x00080000;  /* virtual interrupt flag */
+  DOSVM_SetTimer(0x10000);
+  ret = DOSVM_Enter( &context );
 
-  write_pipe=write_fd[1];
+  dosvm_pid = 0;
+  return ret;
+}
 
-  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);
+static BOOL MZ_InitTask(void)
+{
+  if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+                       GetCurrentProcess(), &loop_thread,
+                       0, FALSE, DUPLICATE_SAME_ACCESS))
     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);
+  dosvm_thread = CreateThread(NULL, 0, MZ_DOSVM, NULL, CREATE_SUSPENDED, &dosvm_tid);
+  if (!dosvm_thread) {
+    CloseHandle(loop_thread);
+    loop_thread = 0;
     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;
+  loop_tid = GetCurrentThreadId();
+  return TRUE;
 }
 
 static void MZ_Launch(void)
 {
-  CONTEXT context;
-  TDB *pTask = GlobalLock16( GetCurrentTask() );
+  TDB *pTask = TASK_GetCurrent();
   BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
 
   MZ_FillPSP(psp_start, GetCommandLineA());
   pTask->flags |= TDBF_WINOLDAP;
 
-  memset( &context, 0, sizeof(context) );
-  context.SegCs  = init_cs;
-  context.Eip    = init_ip;
-  context.SegSs  = init_ss;
-  context.Esp    = init_sp;
-  context.SegDs  = DOSVM_psp;
-  context.SegEs  = DOSVM_psp;
-  context.EFlags = 0x00080000;  /* virtual interrupt flag */
   _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 */
-- 
GitLab