X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2Fwin32%2FTicker.c;h=929e6f4086bef8f08fb49d4c32023c903cd3b7a9;hb=fff1f6194c3c39de53cd645bda9865fb131b1c68;hp=5b41494d47e589c5e7d01fe5f38038b728cb1734;hpb=e30aca19def5c629a8429bd57e56535b7f8f85c8;p=ghc-hetmet.git diff --git a/rts/win32/Ticker.c b/rts/win32/Ticker.c index 5b41494..929e6f4 100644 --- a/rts/win32/Ticker.c +++ b/rts/win32/Ticker.c @@ -3,12 +3,10 @@ * */ #include "Rts.h" -#include "Timer.h" #include "Ticker.h" #include #include #include -#include "OSThreads.h" /* * Provide a timer service for the RTS, periodically @@ -16,15 +14,16 @@ * */ -/* To signal shutdown of the timer service, we use a local - * event which the timer thread listens to (and stopVirtTimer() - * signals.) +/* To signal pause or shutdown of the timer service, we use a local + * event which the timer thread listens to. */ static HANDLE hStopEvent = INVALID_HANDLE_VALUE; static HANDLE tickThread = INVALID_HANDLE_VALUE; static TickProc tickProc = NULL; +static enum { TickerGo, TickerPause, TickerExit } ticker_state; + /* * Ticking is done by a separate thread which periodically * wakes up to handle a tick. @@ -41,41 +40,50 @@ WINAPI TimerProc(PVOID param) { int ms = (int)param; - DWORD waitRes; + DWORD waitRes = 0; /* interpret a < 0 timeout period as 'instantaneous' */ - if (ms < 0) ms = 0; + if (ms < 0) ms = 0; while (1) { - waitRes = WaitForSingleObject(hStopEvent, ms); - - switch (waitRes) { - case WAIT_OBJECT_0: - /* event has become signalled */ - tickProc = NULL; - CloseHandle(hStopEvent); - hStopEvent = INVALID_HANDLE_VALUE; - return 0; - case WAIT_TIMEOUT: - /* tick */ - tickProc(0); - break; - case WAIT_FAILED: { - DWORD dw = GetLastError(); - fprintf(stderr, "TimerProc: wait failed -- error code: %lu\n", dw); fflush(stderr); - break; - } - default: - fprintf(stderr, "TimerProc: unexpected result %lu\n", waitRes); fflush(stderr); - break; - } + switch (ticker_state) { + case TickerGo: + waitRes = WaitForSingleObject(hStopEvent, ms); + break; + case TickerPause: + waitRes = WaitForSingleObject(hStopEvent, INFINITE); + break; + case TickerExit: + /* event has become signalled */ + tickProc = NULL; + CloseHandle(hStopEvent); + hStopEvent = INVALID_HANDLE_VALUE; + return 0; + } + + switch (waitRes) { + case WAIT_OBJECT_0: + /* event has become signalled */ + ResetEvent(hStopEvent); + continue; + case WAIT_TIMEOUT: + /* tick */ + tickProc(0); + break; + case WAIT_FAILED: + sysErrorBelch("TimerProc: WaitForSingleObject failed"); + break; + default: + errorBelch("TimerProc: unexpected result %lu\n", waitRes); + break; + } } return 0; } void -startTicker(nat ms, TickProc handle_tick) +initTicker (nat ms, TickProc handle_tick) { unsigned threadId; /* 'hStopEvent' is a manual-reset event that's signalled upon @@ -86,9 +94,11 @@ startTicker(nat ms, TickProc handle_tick) FALSE, NULL); if (hStopEvent == INVALID_HANDLE_VALUE) { - return 0; + sysErrorBelch("CreateEvent"); + stg_exit(EXIT_FAILURE); } tickProc = handle_tick; + ticker_state = TickerPause; tickThread = (HANDLE)(long)_beginthreadex( NULL, 0, TimerProc, @@ -103,8 +113,22 @@ startTicker(nat ms, TickProc handle_tick) } void +startTicker(void) +{ + ticker_state = TickerGo; + SetEvent(hStopEvent); +} + +void stopTicker(void) { + ticker_state = TickerPause; + SetEvent(hStopEvent); +} + +void +exitTicker (rtsBool wait) +{ // We must wait for the ticker thread to terminate, since if we // are in a DLL that is about to be unloaded, the ticker thread // cannot be allowed to return to a missing DLL. @@ -112,11 +136,22 @@ stopTicker(void) if (hStopEvent != INVALID_HANDLE_VALUE && tickThread != INVALID_HANDLE_VALUE) { DWORD exitCode; + ticker_state = TickerExit; SetEvent(hStopEvent); - while (1) { - WaitForSingleObject(tickThread, 20); + while (wait) { + // See #3748: + // + // when the RTS is compiled into a DLL (wait==rtsTrue), + // the ticker thread must stop before we exit, or chaos + // will ensue. We can't kill it, because it may be + // holding a lock. + // + // When not compiled into a DLL, we wait for + // the thread out of courtesy, but give up after 200ms if + // it still hasn't stopped. + WaitForSingleObject(tickThread, 200); if (!GetExitCodeThread(tickThread, &exitCode)) { - return 1; + return; } if (exitCode != STILL_ACTIVE) { tickThread = INVALID_HANDLE_VALUE; @@ -124,9 +159,8 @@ stopTicker(void) CloseHandle(hStopEvent); hStopEvent = INVALID_HANDLE_VALUE; } - return 0; + return; } - TerminateThread(tickThread, 0); } } }