1 /* -----------------------------------------------------------------------------
2 * $Id: Itimer.c,v 1.8 2000/01/13 12:40:15 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
56 SMP note: this signal could be delivered to *any* thread. We have
57 to ensure that it doesn't matter which thread actually runs the
59 -------------------------------------------------------------------------- */
62 handle_tick(int unused STG_UNUSED)
67 if (do_prof_ticks = rtsTrue) {
72 /* For threadDelay etc., see Select.c */
78 * Handling timer events under cygwin32 is not done with signal/setitimer.
79 * Instead of the two steps of first registering a signal handler to handle
80 * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use
81 * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API
82 * creates a separate thread that will notify the main thread of timer
83 * expiry). -- SOF 7/96
85 * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
88 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
91 vtalrm_handler is assigned and set up in Signals.c
93 vtalrm_id (defined in Signals.c) holds
94 the system id for the current timer (used to
98 TIMECALLBACK *vtalrm_cback;
101 initialize_virtual_timer(nat ms)
104 /* On Win32 setups that don't have support for
105 setitimer(), we use the MultiMedia API's timer
108 As the delivery of ticks isn't free, we only
109 enable it if we really needed, i.e., when profiling.
110 (the RTS now also needs timer ticks to implement
111 threadDelay in non-profiling mode, but the pure
112 Win32 port doesn't support that.....yet.)
114 unsigned int delay,vtalrm_id;
116 delay = timeBeginPeriod(1);
117 if (delay == TIMERR_NOCANDO) { /* error of some sort. */
121 timeSetEvent(ms, /* event every `delay' milliseconds. */
122 1, /* precision is within 5 millisecs. */
123 (LPTIMECALLBACK)vtalrm_cback,
133 initialize_virtual_timer(nat ms)
135 # ifndef HAVE_SETITIMER
136 fprintf(stderr, "No virtual timer on this system\n");
141 it.it_value.tv_sec = ms / 1000;
142 it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
143 it.it_interval = it.it_value;
144 return (setitimer(ITIMER_VIRTUAL, &it, NULL));
148 #endif /* !cygwin32_TARGET_OS */
151 /* This is a potential POSIX version */
153 initialize_virtual_timer(nat ms)
156 struct itimerspec it;
159 se.sigev_notify = SIGEV_SIGNAL;
160 se.sigev_signo = SIGVTALRM;
161 se.sigev_value.sival_int = SIGVTALRM;
162 if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
163 barf("can't create virtual timer");
165 it.it_value.tv_sec = ms / 1000;
166 it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
167 it.it_interval = it.it_value;
168 timer_settime(tid, TIMER_RELTIME, &it, NULL);
172 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
174 install_vtalrm_handler(void)
176 vtalrm_cback = handle_tick;
182 install_vtalrm_handler(void)
184 struct sigaction action;
186 action.sa_handler = handle_tick;
188 sigemptyset(&action.sa_mask);
191 return sigaction(SIGVTALRM, &action, NULL);
195 block_vtalrm_signal(void)
199 sigemptyset(&signals);
200 sigaddset(&signals, SIGVTALRM);
202 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
206 unblock_vtalrm_signal(void)
210 sigemptyset(&signals);
211 sigaddset(&signals, SIGVTALRM);
213 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);