#include <windows.h>
#include <stdio.h>
#include "Schedule.h"
+#include "RtsFlags.h"
+#include "Capability.h"
#include "win32/AsyncIO.h"
#include "win32/IOManager.h"
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
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
issued_reqs--;
if (completed_hw == 1) {
/* The event is used to wake up the scheduler thread should it
- * be blocked waiting for requests to complete. It reset once
+ * be blocked waiting for requests to complete. The event resets once
* that thread has cleared out the request queue/table.
*/
SetEvent(completed_req_event);
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
int
awaitRequests(rtsBool wait)
{
+#ifndef THREADED_RTS
+ // none of this is actually used in the threaded RTS
+
start:
#if 0
fprintf(stderr, "awaitRequests(): %d %d %d\n", issued_reqs, completed_hw, wait);
#endif
EnterCriticalSection(&queue_lock);
/* Nothing immediately available & we won't wait */
- if ((!wait && completed_hw == 0) ||
- (issued_reqs == 0 && completed_hw == 0)) {
+ if ((!wait && completed_hw == 0)
+#if 0
+ // If we just return when wait==rtsFalse, we'll go into a busy
+ // wait loop, so I disabled this condition --SDM 18/12/2003
+ (issued_reqs == 0 && completed_hw == 0)
+#endif
+ ) {
LeaveCriticalSection(&queue_lock);
return 0;
}
DWORD dwRes = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
switch (dwRes) {
case WAIT_OBJECT_0:
+ /* a request was completed */
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
+ /* timeout (unlikely) or told to abandon waiting */
return 0;
+ case WAIT_FAILED: {
+ DWORD dw = GetLastError();
+ fprintf(stderr, "awaitRequests: wait failed -- error code: %lu\n", dw); fflush(stderr);
+ return 0;
+ }
default:
fprintf(stderr, "awaitRequests: unexpected wait return code %lu\n", dwRes); fflush(stderr);
return 0;
}
} else {
- return 0; /* cannot happen */
+ return 0;
}
goto start;
} else {
*
*/
unsigned int rID = completedTable[i].reqID;
- prev = NULL;
prev = NULL;
for(tso = blocked_queue_hd ; tso != END_TSO_QUEUE; prev = tso, tso = tso->link) {
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);
LeaveCriticalSection(&queue_lock);
return 1;
}
+#endif /* !THREADED_RTS */
}
/*
* to complete (via awaitRequests().)
*/
void
-abandonRequestWait()
+abandonRequestWait( void )
{
/* 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.
+ *
+ * Careful! There is no synchronisation between
+ * abandonRequestWait and awaitRequest, which means that
+ * abandonRequestWait might be called just before a thread
+ * goes into a wait, and we miss the abandon signal. So we
+ * must SetEvent() here rather than PulseEvent() to ensure
+ * that the event isn't lost. We can re-optimise by resetting
+ * the event somewhere safe if we know the event has been
+ * properly serviced (see resetAbandon() below). --SDM 18/12/2003
*/
- PulseEvent(abandon_req_wait);
+ SetEvent(abandon_req_wait);
}
+
+void
+resetAbandonRequestWait( void )
+{
+ ResetEvent(abandon_req_wait);
+}
+