1 /* -----------------------------------------------------------------------------
2 * $Id: Itimer.c,v 1.5 1999/08/25 16:11:48 simonmar Exp $
4 * (c) The GHC Team, 1995-1999
6 * Interval timer for profiling and pre-emptive scheduling.
8 * ---------------------------------------------------------------------------*/
11 * The interval timer is used for profiling and for context switching in the
12 * threaded build. Though POSIX 1003.1b includes a standard interface for
13 * such things, no one really seems to be implementing them yet. Even
14 * Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
15 * keen on getting access to @CLOCK_VIRTUAL@.
17 * Hence, we use the old-fashioned @setitimer@ that just about everyone seems
18 * to support. So much for standards.
22 # define NON_POSIX_SOURCE
29 /* As recommended in the autoconf manual */
30 # ifdef TIME_WITH_SYS_TIME
31 # include <sys/time.h>
34 # ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
46 rtsBool do_prof_ticks = rtsFalse;
48 static void handle_tick(int unused STG_UNUSED);
50 /* -----------------------------------------------------------------------------
53 We use the ticker for two things: supporting threadDelay, and time
55 -------------------------------------------------------------------------- */
58 handle_tick(int unused STG_UNUSED)
63 if (do_prof_ticks = rtsTrue) {
68 /* For threadDelay etc., see Select.c */
74 * Handling timer events under cygwin32 is not done with signal/setitimer.
75 * Instead of the two steps of first registering a signal handler to handle
76 * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use
77 * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API
78 * creates a separate thread that will notify the main thread of timer
79 * expiry). -- SOF 7/96
81 * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
84 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
87 vtalrm_handler is assigned and set up in Signals.c
89 vtalrm_id (defined in Signals.c) holds
90 the system id for the current timer (used to
94 TIMECALLBACK *vtalrm_cback;
97 initialize_virtual_timer(nat ms)
99 /* VTALRM is currently not supported by cygwin32,
100 so we use the Timer support provided by the
101 MultiMedia API that is part of Win32. The
102 parameters to timeSetEvent may require some tweaking.
104 unsigned int delay,vtalrm_id;
106 delay = timeBeginPeriod(1);
107 if (delay == TIMERR_NOCANDO) { /* error of some sort. */
111 timeSetEvent(ms, /* event every `delay' milliseconds. */
112 1, /* precision is within 5 millisecs. */
113 (LPTIMECALLBACK)vtalrm_cback,
122 initialize_virtual_timer(nat ms)
124 # ifndef HAVE_SETITIMER
125 fprintf(stderr, "No virtual timer on this system\n");
130 it.it_value.tv_sec = ms / 1000;
131 it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
132 it.it_interval = it.it_value;
133 return (setitimer(ITIMER_VIRTUAL, &it, NULL));
137 #endif /* !cygwin32_TARGET_OS */
140 /* This is a potential POSIX version */
142 initialize_virtual_timer(nat ms)
145 struct itimerspec it;
148 se.sigev_notify = SIGEV_SIGNAL;
149 se.sigev_signo = SIGVTALRM;
150 se.sigev_value.sival_int = SIGVTALRM;
151 if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
152 fprintf(stderr, "Can't create virtual timer.\n");
155 it.it_value.tv_sec = ms / 1000;
156 it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
157 it.it_interval = it.it_value;
158 timer_settime(tid, TIMER_RELTIME, &it, NULL);
162 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
164 install_vtalrm_handler(void)
166 vtalrm_cback = handle_tick;
172 install_vtalrm_handler(void)
174 struct sigaction action;
176 action.sa_handler = handle_tick;
178 sigemptyset(&action.sa_mask);
181 return sigaction(SIGVTALRM, &action, NULL);
185 block_vtalrm_signal(void)
189 sigemptyset(&signals);
190 sigaddset(&signals, SIGVTALRM);
192 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
196 unblock_vtalrm_signal(void)
200 sigemptyset(&signals);
201 sigaddset(&signals, SIGVTALRM);
203 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);