/* ----------------------------------------------------------------------------- * * (c) The GHC Team, 1998-2006 * * The IO manager thread in THREADED_RTS. * See also libraries/base/GHC/Conc.hs. * * ---------------------------------------------------------------------------*/ #include "Rts.h" #include "IOManager.h" #include "Prelude.h" #include // Here's the Event that we use to wake up the IO manager thread static HANDLE io_manager_event = INVALID_HANDLE_VALUE; // must agree with values in GHC.Conc: #define IO_MANAGER_WAKEUP 0xffffffff #define IO_MANAGER_DIE 0xfffffffe // spurios wakeups are returned as zero. // console events are ((event<<1) | 1) #if defined(THREADED_RTS) #define EVENT_BUFSIZ 256 Mutex event_buf_mutex; StgWord32 event_buf[EVENT_BUFSIZ]; uint32_t next_event; #endif HANDLE getIOManagerEvent (void) { // This function has to exist even in the non-THREADED_RTS, // because code in GHC.Conc refers to it. It won't ever be called // unless we're in the threaded RTS, however. #if defined(THREADED_RTS) HANDLE hRes; ACQUIRE_LOCK(&event_buf_mutex); if (io_manager_event == INVALID_HANDLE_VALUE) { hRes = CreateEvent ( NULL, // no security attrs true, // manual reset false, // initial state, NULL ); // event name: NULL for private events if (hRes == NULL) { sysErrorBelch("getIOManagerEvent"); stg_exit(EXIT_FAILURE); } io_manager_event = hRes; } else { hRes = io_manager_event; } RELEASE_LOCK(&event_buf_mutex); return hRes; #else return NULL; #endif } HsWord32 readIOManagerEvent (void) { // This function must exist even in non-THREADED_RTS, // see getIOManagerEvent() above. #if defined(THREADED_RTS) HsWord32 res; ACQUIRE_LOCK(&event_buf_mutex); if (io_manager_event != INVALID_HANDLE_VALUE) { if (next_event == 0) { res = 0; // no event to return } else { res = (HsWord32)(event_buf[--next_event]); if (next_event == 0) { if (!ResetEvent(io_manager_event)) { sysErrorBelch("readIOManagerEvent"); stg_exit(EXIT_FAILURE); } } } } else { res = 0; } RELEASE_LOCK(&event_buf_mutex); // debugBelch("readIOManagerEvent: %d\n", res); return res; #else return 0; #endif } void sendIOManagerEvent (HsWord32 event) { #if defined(THREADED_RTS) ACQUIRE_LOCK(&event_buf_mutex); // debugBelch("sendIOManagerEvent: %d\n", event); if (io_manager_event != INVALID_HANDLE_VALUE) { if (next_event == EVENT_BUFSIZ) { errorBelch("event buffer overflowed; event dropped"); } else { if (!SetEvent(io_manager_event)) { sysErrorBelch("sendIOManagerEvent"); stg_exit(EXIT_FAILURE); } event_buf[next_event++] = (StgWord32)event; } } RELEASE_LOCK(&event_buf_mutex); #endif } void ioManagerWakeup (void) { sendIOManagerEvent(IO_MANAGER_WAKEUP); } #if defined(THREADED_RTS) void ioManagerDie (void) { sendIOManagerEvent(IO_MANAGER_DIE); // IO_MANAGER_DIE must be idempotent, as it is called // repeatedly by shutdownCapability(). Try conc059(threaded1) to // illustrate the problem. ACQUIRE_LOCK(&event_buf_mutex); io_manager_event = INVALID_HANDLE_VALUE; RELEASE_LOCK(&event_buf_mutex); // ToDo: wait for the IO manager to pick up the event, and // then release the Event and Mutex objects we've allocated. } void ioManagerStart (void) { initMutex(&event_buf_mutex); next_event = 0; // Make sure the IO manager thread is running Capability *cap; if (io_manager_event == INVALID_HANDLE_VALUE) { cap = rts_lock(); rts_evalIO(&cap, ensureIOManagerIsRunning_closure, NULL); rts_unlock(cap); } } #endif