*
*/
-/* 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.
DWORD waitRes;
/* 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);
- 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;
}
-int
-startTicker(nat ms, TickProc handle_tick)
+void
+initTicker (nat ms, TickProc handle_tick)
{
unsigned threadId;
/* 'hStopEvent' is a manual-reset event that's signalled upon
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,
(LPVOID)ms,
0,
&threadId);
- return (tickThread != 0);
+
+ if (tickThread == 0) {
+ sysErrorBelch("_beginthreadex");
+ stg_exit(EXIT_FAILURE);
+ }
}
-int
+void
+startTicker(void)
+{
+ ticker_state = TickerGo;
+ SetEvent(hStopEvent);
+}
+
+void
stopTicker(void)
{
+ ticker_state = TickerPause;
+ SetEvent(hStopEvent);
+}
+
+void
+exitTicker(void)
+{
// 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.
if (hStopEvent != INVALID_HANDLE_VALUE &&
tickThread != INVALID_HANDLE_VALUE) {
DWORD exitCode;
+ ticker_state = TickerExit;
SetEvent(hStopEvent);
while (1) {
WaitForSingleObject(tickThread, 20);
}
if (exitCode != STILL_ACTIVE) {
tickThread = INVALID_HANDLE_VALUE;
- CloseHandle(hStopEvent);
+ if ( hStopEvent != INVALID_HANDLE_VALUE ) {
+ CloseHandle(hStopEvent);
+ hStopEvent = INVALID_HANDLE_VALUE;
+ }
return 0;
}
TerminateThread(tickThread, 0);
}
}
- return 0;
}