stopTicker(): wait for the timer thread to exit
[ghc-hetmet.git] / ghc / 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     return 0;
44
45   int ms = (int)param;
46   DWORD waitRes;
47   
48   /* interpret a < 0 timeout period as 'instantaneous' */ 
49  if (ms < 0) ms = 0;
50
51   while (1) {
52     waitRes = WaitForSingleObject(hStopEvent, ms);
53     
54     switch (waitRes) {
55     case WAIT_OBJECT_0:
56       /* event has become signalled */
57       tickProc = NULL;
58       CloseHandle(hStopEvent);
59       return 0;
60     case WAIT_TIMEOUT:
61       /* tick */
62       tickProc(0);
63       break;
64     case WAIT_FAILED: {
65         DWORD dw = GetLastError();
66         fprintf(stderr, "TimerProc: wait failed -- error code: %lu\n", dw); fflush(stderr);
67         break; 
68     }
69     default:
70       fprintf(stderr, "TimerProc: unexpected result %lu\n", waitRes); fflush(stderr);
71       break;
72     }
73   }
74   return 0;
75 }
76
77
78 int
79 startTicker(nat ms, TickProc handle_tick)
80 {
81   unsigned threadId;
82   /* 'hStopEvent' is a manual-reset event that's signalled upon
83    * shutdown of timer service (=> timer thread.)
84    */
85   hStopEvent = CreateEvent ( NULL,
86                              TRUE,
87                              FALSE,
88                              NULL);
89   if (hStopEvent == INVALID_HANDLE_VALUE) {
90     return 0;
91   }
92   tickProc = handle_tick;
93   tickThread = (HANDLE)(long)_beginthreadex( NULL,
94                                0,
95                                TimerProc,
96                                (LPVOID)ms,
97                                0,
98                                &threadId);
99   return (tickThread != 0);
100 }
101
102 int
103 stopTicker(void)
104 {
105     // We must wait for the ticker thread to terminate, since if we
106     // are in a DLL that is about to be unloaded, the ticker thread
107     // cannot be allowed to return to a missing DLL.
108
109     if (hStopEvent != INVALID_HANDLE_VALUE && 
110         tickThread != INVALID_HANDLE_VALUE) {
111         DWORD exitCode;
112         SetEvent(hStopEvent);
113         while (1) {
114             WaitForSingleObject(tickThread, 20);
115             if (!GetExitCodeThread(tickThread, &exitCode)) {
116                 return 1;
117             }
118             if (exitCode != STILL_ACTIVE) {
119                 tickThread = INVALID_HANDLE_VALUE;
120                 return 0;
121             }
122             TerminateThread(tickThread, 0);
123         }
124     }
125     return 0;
126 }