Ticker.c 2.72 KB
Newer Older
sof's avatar
sof committed
1
2
3
4
5
6
7
8
9
10
/*
 * RTS periodic timers.
 * 
 */
#include "Rts.h"
#include "Timer.h"
#include "Ticker.h"
#include <windows.h>
#include <stdio.h>
#include <process.h>
11
#include "OSThreads.h"
sof's avatar
sof committed
12
13
14
15
16
17
18
19
20
21
22
23

/*
 * Provide a timer service for the RTS, periodically
 * notifying it that a number of 'ticks' has passed.
 *
 */

/* To signal shutdown of the timer service, we use a local
 * event which the timer thread listens to (and stopVirtTimer()
 * signals.)
 */
static HANDLE hStopEvent = INVALID_HANDLE_VALUE;
24
static HANDLE tickThread = INVALID_HANDLE_VALUE;
sof's avatar
sof committed
25

sof's avatar
sof committed
26
27
static TickProc tickProc = NULL;

sof's avatar
sof committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
 * Ticking is done by a separate thread which periodically
 * wakes up to handle a tick.
 *
 * This is the portable way of providing a timer service under
 * Win32; features like waitable timers or timer queues are only
 * supported by a subset of the Win32 platforms (notably not
 * under Win9x.)
 *
 */
static
unsigned
WINAPI
TimerProc(PVOID param)
{
  int ms = (int)param;
  DWORD waitRes;
  
46
47
  /* interpret a < 0 timeout period as 'instantaneous' */ 
 if (ms < 0) ms = 0;
sof's avatar
sof committed
48
49
50
51
52
53
54

  while (1) {
    waitRes = WaitForSingleObject(hStopEvent, ms);
    
    switch (waitRes) {
    case WAIT_OBJECT_0:
      /* event has become signalled */
sof's avatar
sof committed
55
      tickProc = NULL;
sof's avatar
sof committed
56
57
58
59
      CloseHandle(hStopEvent);
      return 0;
    case WAIT_TIMEOUT:
      /* tick */
sof's avatar
sof committed
60
      tickProc(0);
sof's avatar
sof committed
61
      break;
sof's avatar
sof committed
62
63
64
65
66
    case WAIT_FAILED: {
	DWORD dw = GetLastError();
	fprintf(stderr, "TimerProc: wait failed -- error code: %lu\n", dw); fflush(stderr);
	break; 
    }
sof's avatar
sof committed
67
    default:
sof's avatar
sof committed
68
      fprintf(stderr, "TimerProc: unexpected result %lu\n", waitRes); fflush(stderr);
sof's avatar
sof committed
69
70
71
72
73
74
75
76
      break;
    }
  }
  return 0;
}


int
sof's avatar
sof committed
77
startTicker(nat ms, TickProc handle_tick)
sof's avatar
sof committed
78
{
sof's avatar
sof committed
79
  unsigned threadId;
sof's avatar
sof committed
80
81
82
83
84
85
86
87
88
89
  /* 'hStopEvent' is a manual-reset event that's signalled upon
   * shutdown of timer service (=> timer thread.)
   */
  hStopEvent = CreateEvent ( NULL,
			     TRUE,
			     FALSE,
			     NULL);
  if (hStopEvent == INVALID_HANDLE_VALUE) {
    return 0;
  }
sof's avatar
sof committed
90
  tickProc = handle_tick;
91
  tickThread = (HANDLE)(long)_beginthreadex( NULL,
sof's avatar
sof committed
92
93
94
95
			       0,
			       TimerProc,
			       (LPVOID)ms,
			       0,
96
97
			       &threadId);
  return (tickThread != 0);
sof's avatar
sof committed
98
99
100
101
102
}

int
stopTicker(void)
{
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    // 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;
	SetEvent(hStopEvent);
	while (1) {
	    WaitForSingleObject(tickThread, 20);
	    if (!GetExitCodeThread(tickThread, &exitCode)) {
		return 1;
	    }
	    if (exitCode != STILL_ACTIVE) {
		tickThread = INVALID_HANDLE_VALUE;
		return 0;
	    }
	    TerminateThread(tickThread, 0);
	}
    }
    return 0;
sof's avatar
sof committed
124
}