[project @ 2003-07-23 13:08:22 by simonpj]
[ghc-hetmet.git] / ghc / rts / win32 / AsyncIO.c
index 8b15470..bc153a9 100644 (file)
@@ -5,6 +5,7 @@
  * (c) sof, 2002-2003.
  */
 #include "Rts.h"
+#include "RtsUtils.h"
 #include <windows.h>
 #include <stdio.h>
 #include "Schedule.h"
@@ -43,16 +44,17 @@ typedef struct CompletedReq {
 
 static CRITICAL_SECTION queue_lock;
 static HANDLE           completed_req_event;
+static HANDLE           abandon_req_wait;
+static HANDLE           wait_handles[2];
 static CompletedReq     completedTable[MAX_REQUESTS];
 static int              completed_hw;
 static int              issued_reqs;
 
 static void
 onIOComplete(unsigned int reqID,
-            void* param STG_UNUSED,
             int   fd STG_UNUSED,
             int   len,
-            char* buf STG_UNUSED,
+            void* buf STG_UNUSED,
             int   errCode)
 {
   /* Deposit result of request in queue/table */
@@ -94,9 +96,34 @@ addIORequest(int   fd,
 #if 0
   fprintf(stderr, "addIOReq: %d %d %d\n", fd, forWriting, len); fflush(stderr);
 #endif
-  return AddIORequest(fd,forWriting,isSock,len,buf,0,onIOComplete);
+  return AddIORequest(fd,forWriting,isSock,len,buf,onIOComplete);
 }
 
+unsigned int
+addDelayRequest(int msecs)
+{
+  EnterCriticalSection(&queue_lock);
+  issued_reqs++;
+  LeaveCriticalSection(&queue_lock);
+#if 0
+  fprintf(stderr, "addDelayReq: %d\n", msecs); fflush(stderr);
+#endif
+  return AddDelayRequest(msecs,onIOComplete);
+}
+
+unsigned int
+addDoProcRequest(void* proc, void* param)
+{
+  EnterCriticalSection(&queue_lock);
+  issued_reqs++;
+  LeaveCriticalSection(&queue_lock);
+#if 0
+  fprintf(stderr, "addProcReq: %p %p\n", proc, param); fflush(stderr);
+#endif
+  return AddProcRequest(proc,param,onIOComplete);
+}
+
+
 int
 startupAsyncIO()
 {
@@ -104,9 +131,20 @@ startupAsyncIO()
     return 0;
   }
   InitializeCriticalSection(&queue_lock);
-  completed_req_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+  /* Create a pair of events:
+   *
+   *    - completed_req_event  -- signals the deposit of request result; manual reset.
+   *    - abandon_req_wait     -- external OS thread tells current RTS/Scheduler
+   *                              thread to abandon wait for IO request completion.
+   *                              Auto reset.
+   */
+  completed_req_event = CreateEvent (NULL, TRUE,  FALSE, NULL);
+  abandon_req_wait    = CreateEvent (NULL, FALSE, FALSE, NULL);
+  wait_handles[0] = completed_req_event;
+  wait_handles[1] = abandon_req_wait;
   completed_hw = 0;
-  return 1;
+  return ( completed_req_event != INVALID_HANDLE_VALUE &&
+          abandon_req_wait    != INVALID_HANDLE_VALUE );
 }
 
 void
@@ -134,7 +172,17 @@ start:
     /* empty table, drop lock and wait */
     LeaveCriticalSection(&queue_lock);
     if (wait) {
-      WaitForSingleObject( completed_req_event, INFINITE );
+      DWORD dwRes = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
+      switch (dwRes) {
+      case WAIT_OBJECT_0:
+       break;
+      case WAIT_OBJECT_0 + 1:
+      case WAIT_TIMEOUT:
+       return 0;
+      default:
+       fprintf(stderr, "awaitRequests: unexpected wait return code %lu\n", dwRes); fflush(stderr);
+       return 0;
+      }
     } else {
       return 0; /* cannot happen */
     }
@@ -150,6 +198,7 @@ start:
        switch(tso->why_blocked) {
        case BlockedOnRead:
        case BlockedOnWrite:
+       case BlockedOnDoProc:
          if (tso->block_info.async_result->reqID == rID) {
            /* Found the thread blocked waiting on request; stodgily fill 
             * in its result block. 
@@ -174,6 +223,9 @@ start:
          }
          break;
        default:
+         if (tso->why_blocked != NotBlocked) {
+             barf("awaitRequests: odd thread state");
+         }
          break;
        }
        prev = tso;
@@ -185,3 +237,13 @@ start:
     return 1;
   }
 }
+
+void
+abandonRequestWait()
+{
+  /* the event is auto-reset, but in case there's no thread
+   * already waiting on the event, we want to return it to
+   * a non-signalled state.
+   */
+  PulseEvent(abandon_req_wait);
+}