5b41494d47e589c5e7d01fe5f38038b728cb1734
[ghc.git] / rts / win32 / Ticker.c
1 /*
2 * RTS periodic timers.
3 *
4 */
5 #include "Rts.h"
6 #include "Timer.h"
7 #include "Ticker.h"
8 #include <windows.h>
9 #include <stdio.h>
10 #include <process.h>
11 #include "OSThreads.h"
12
13 /*
14 * Provide a timer service for the RTS, periodically
15 * notifying it that a number of 'ticks' has passed.
16 *
17 */
18
19 /* To signal shutdown of the timer service, we use a local
20 * event which the timer thread listens to (and stopVirtTimer()
21 * signals.)
22 */
23 static HANDLE hStopEvent = INVALID_HANDLE_VALUE;
24 static HANDLE tickThread = INVALID_HANDLE_VALUE;
25
26 static TickProc tickProc = NULL;
27
28 /*
29 * Ticking is done by a separate thread which periodically
30 * wakes up to handle a tick.
31 *
32 * This is the portable way of providing a timer service under
33 * Win32; features like waitable timers or timer queues are only
34 * supported by a subset of the Win32 platforms (notably not
35 * under Win9x.)
36 *
37 */
38 static
39 unsigned
40 WINAPI
41 TimerProc(PVOID param)
42 {
43 int ms = (int)param;
44 DWORD waitRes;
45
46 /* interpret a < 0 timeout period as 'instantaneous' */
47 if (ms < 0) ms = 0;
48
49 while (1) {
50 waitRes = WaitForSingleObject(hStopEvent, ms);
51
52 switch (waitRes) {
53 case WAIT_OBJECT_0:
54 /* event has become signalled */
55 tickProc = NULL;
56 CloseHandle(hStopEvent);
57 hStopEvent = INVALID_HANDLE_VALUE;
58 return 0;
59 case WAIT_TIMEOUT:
60 /* tick */
61 tickProc(0);
62 break;
63 case WAIT_FAILED: {
64 DWORD dw = GetLastError();
65 fprintf(stderr, "TimerProc: wait failed -- error code: %lu\n", dw); fflush(stderr);
66 break;
67 }
68 default:
69 fprintf(stderr, "TimerProc: unexpected result %lu\n", waitRes); fflush(stderr);
70 break;
71 }
72 }
73 return 0;
74 }
75
76
77 void
78 startTicker(nat ms, TickProc handle_tick)
79 {
80 unsigned threadId;
81 /* 'hStopEvent' is a manual-reset event that's signalled upon
82 * shutdown of timer service (=> timer thread.)
83 */
84 hStopEvent = CreateEvent ( NULL,
85 TRUE,
86 FALSE,
87 NULL);
88 if (hStopEvent == INVALID_HANDLE_VALUE) {
89 return 0;
90 }
91 tickProc = handle_tick;
92 tickThread = (HANDLE)(long)_beginthreadex( NULL,
93 0,
94 TimerProc,
95 (LPVOID)ms,
96 0,
97 &threadId);
98
99 if (tickThread == 0) {
100 sysErrorBelch("_beginthreadex");
101 stg_exit(EXIT_FAILURE);
102 }
103 }
104
105 void
106 stopTicker(void)
107 {
108 // We must wait for the ticker thread to terminate, since if we
109 // are in a DLL that is about to be unloaded, the ticker thread
110 // cannot be allowed to return to a missing DLL.
111
112 if (hStopEvent != INVALID_HANDLE_VALUE &&
113 tickThread != INVALID_HANDLE_VALUE) {
114 DWORD exitCode;
115 SetEvent(hStopEvent);
116 while (1) {
117 WaitForSingleObject(tickThread, 20);
118 if (!GetExitCodeThread(tickThread, &exitCode)) {
119 return 1;
120 }
121 if (exitCode != STILL_ACTIVE) {
122 tickThread = INVALID_HANDLE_VALUE;
123 if ( hStopEvent != INVALID_HANDLE_VALUE ) {
124 CloseHandle(hStopEvent);
125 hStopEvent = INVALID_HANDLE_VALUE;
126 }
127 return 0;
128 }
129 TerminateThread(tickThread, 0);
130 }
131 }
132 }