1 /* -----------------------------------------------------------------------------
2 * $Id: Itimer.c,v 1.6 1999/09/16 08:33:54 sof 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)
100 /* On Win32 setups that don't have support for
101 setitimer(), we use the MultiMedia API's timer
104 As the delivery of ticks isn't free, we only
105 enable it if we really needed, i.e., when profiling.
106 (the RTS now also needs timer ticks to implement
107 threadDelay in non-profiling mode, but the pure
108 Win32 port doesn't support that.....yet.)
110 unsigned int delay,vtalrm_id;
112 delay = timeBeginPeriod(1);
113 if (delay == TIMERR_NOCANDO) { /* error of some sort. */
117 timeSetEvent(ms, /* event every `delay' milliseconds. */
118 1, /* precision is within 5 millisecs. */
119 (LPTIMECALLBACK)vtalrm_cback,
129 initialize_virtual_timer(nat ms)
131 # ifndef HAVE_SETITIMER
132 fprintf(stderr, "No virtual timer on this system\n");
137 it.it_value.tv_sec = ms / 1000;
138 it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
139 it.it_interval = it.it_value;
140 return (setitimer(ITIMER_VIRTUAL, &it, NULL));
144 #endif /* !cygwin32_TARGET_OS */
147 /* This is a potential POSIX version */
149 initialize_virtual_timer(nat ms)
152 struct itimerspec it;
155 se.sigev_notify = SIGEV_SIGNAL;
156 se.sigev_signo = SIGVTALRM;
157 se.sigev_value.sival_int = SIGVTALRM;
158 if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
159 fprintf(stderr, "Can't create virtual timer.\n");
162 it.it_value.tv_sec = ms / 1000;
163 it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
164 it.it_interval = it.it_value;
165 timer_settime(tid, TIMER_RELTIME, &it, NULL);
169 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
171 install_vtalrm_handler(void)
173 vtalrm_cback = handle_tick;
179 install_vtalrm_handler(void)
181 struct sigaction action;
183 action.sa_handler = handle_tick;
185 sigemptyset(&action.sa_mask);
188 return sigaction(SIGVTALRM, &action, NULL);
192 block_vtalrm_signal(void)
196 sigemptyset(&signals);
197 sigaddset(&signals, SIGVTALRM);
199 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
203 unblock_vtalrm_signal(void)
207 sigemptyset(&signals);
208 sigaddset(&signals, SIGVTALRM);
210 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);