[project @ 2005-07-29 20:21:50 by sof]
authorsof <unknown>
Fri, 29 Jul 2005 20:21:50 +0000 (20:21 +0000)
committersof <unknown>
Fri, 29 Jul 2005 20:21:50 +0000 (20:21 +0000)
win32/AsyncIO.c:onIOComplete(), awaitRequests():
  Avoid completion table overflow through the use of
  a semaphore. Worker threads (the producers) wait for a free
  event slot to appear, the RTS thread (consumer) signal slot
  availability once the completion event has been de-queued and
  processed.

  This bug only manifests itself in 'massively concurrent' code
  (>200 threads), where the threads simultaneously engage in IO
  through the async IO layer. conc023 and conc036 in the regression
  test suite are examples of such.

Merge to STABLE.

ghc/rts/win32/AsyncIO.c

index 91495d5..acb40eb 100644 (file)
@@ -50,6 +50,7 @@ static HANDLE           abandon_req_wait;
 static HANDLE           wait_handles[2];
 static CompletedReq     completedTable[MAX_REQUESTS];
 static int              completed_hw;
+static HANDLE           completed_table_sema;
 static int              issued_reqs;
 
 static void
@@ -59,11 +60,22 @@ onIOComplete(unsigned int reqID,
             void* buf STG_UNUSED,
             int   errCode)
 {
-    /* Deposit result of request in queue/table */
+    DWORD dwRes;
+    /* Deposit result of request in queue/table..when there's room. */
+    dwRes = WaitForSingleObject(completed_table_sema, INFINITE);
+    switch (dwRes) {
+    case WAIT_OBJECT_0:
+       break;
+    default:
+       /* Not likely */
+       fprintf(stderr, "onIOComplete: failed to grab table semaphore, dropping request 0x%x\n", reqID);
+       fflush(stderr);
+       return;
+    }
     EnterCriticalSection(&queue_lock);
     if (completed_hw == MAX_REQUESTS) {
-       /* Not likely */
-       fprintf(stderr, "Request table overflow (%d); dropping.\n", reqID);
+       /* Shouldn't happen */
+       fprintf(stderr, "onIOComplete: ERROR -- Request table overflow (%d); dropping.\n", reqID);
        fflush(stderr);
     } else {
 #if 0
@@ -147,8 +159,15 @@ startupAsyncIO()
     wait_handles[0] = completed_req_event;
     wait_handles[1] = abandon_req_wait;
     completed_hw = 0;
-    return ( completed_req_event != INVALID_HANDLE_VALUE &&
-            abandon_req_wait    != INVALID_HANDLE_VALUE );
+    if ( !(completed_table_sema = CreateSemaphore (NULL, MAX_REQUESTS, MAX_REQUESTS, NULL)) ) {
+       DWORD rc = GetLastError();
+       fprintf(stderr, "startupAsyncIO: CreateSemaphore failed 0x%x\n", rc);
+       fflush(stderr);
+    }
+
+    return ( completed_req_event  != INVALID_HANDLE_VALUE &&
+            abandon_req_wait     != INVALID_HANDLE_VALUE &&
+            completed_table_sema != NULL );
 }
 
 void
@@ -275,6 +294,12 @@ start:
                    break;
                }
            }
+           /* Signal that there's completed table slots available */
+           if ( !ReleaseSemaphore(completed_table_sema, 1, NULL) ) {
+               DWORD dw = GetLastError();
+               fprintf(stderr, "awaitRequests: failed to signal semaphore (error code=0x%x)\n", dw);
+               fflush(stderr);
+           }
        }
        completed_hw = 0;
        ResetEvent(completed_req_event);