c1390b7d7642bf4629c43086c6943f4c849f1ff2
[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
12 /*
13  * Provide a timer service for the RTS, periodically
14  * notifying it that a number of 'ticks' has passed.
15  *
16  */
17
18 /* To signal shutdown of the timer service, we use a local
19  * event which the timer thread listens to (and stopVirtTimer()
20  * signals.)
21  */
22 static HANDLE hStopEvent = INVALID_HANDLE_VALUE;
23
24 static TickProc tickProc = NULL;
25
26 /*
27  * Ticking is done by a separate thread which periodically
28  * wakes up to handle a tick.
29  *
30  * This is the portable way of providing a timer service under
31  * Win32; features like waitable timers or timer queues are only
32  * supported by a subset of the Win32 platforms (notably not
33  * under Win9x.)
34  *
35  */
36 static
37 unsigned
38 WINAPI
39 TimerProc(PVOID param)
40 {
41   int ms = (int)param;
42   DWORD waitRes;
43   
44   /* interpret a < 0 timeout period as 'instantaneous' */
45   if (ms < 0) ms = 0;
46
47   while (1) {
48     waitRes = WaitForSingleObject(hStopEvent, ms);
49     
50     switch (waitRes) {
51     case WAIT_OBJECT_0:
52       /* event has become signalled */
53       tickProc = NULL;
54       CloseHandle(hStopEvent);
55       return 0;
56     case WAIT_TIMEOUT:
57       /* tick */
58       tickProc(0);
59       break;
60     case WAIT_FAILED: {
61         DWORD dw = GetLastError();
62         fprintf(stderr, "TimerProc: wait failed -- error code: %lu\n", dw); fflush(stderr);
63         break; 
64     }
65     default:
66       fprintf(stderr, "TimerProc: unexpected result %lu\n", waitRes); fflush(stderr);
67       break;
68     }
69   }
70   return 0;
71 }
72
73
74 int
75 startTicker(nat ms, TickProc handle_tick)
76 {
77   unsigned threadId;
78   /* 'hStopEvent' is a manual-reset event that's signalled upon
79    * shutdown of timer service (=> timer thread.)
80    */
81   hStopEvent = CreateEvent ( NULL,
82                              TRUE,
83                              FALSE,
84                              NULL);
85   if (hStopEvent == INVALID_HANDLE_VALUE) {
86     return 0;
87   }
88   tickProc = handle_tick;
89   return ( 0 != _beginthreadex(NULL,
90                                0,
91                                TimerProc,
92                                (LPVOID)ms,
93                                0,
94                                &threadId) );
95 }
96
97 int
98 stopTicker(void)
99 {
100   if (hStopEvent != INVALID_HANDLE_VALUE) {
101     SetEvent(hStopEvent);
102   }
103   return 0;
104 }