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