1 /* -----------------------------------------------------------------------------
2 * $Id: Itimer.c,v 1.16 2000/08/03 11:28:35 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
28 #include "Proftimer.h"
31 /* As recommended in the autoconf manual */
32 # ifdef TIME_WITH_SYS_TIME
33 # include <sys/time.h>
36 # ifdef HAVE_SYS_TIME_H
37 # include <sys/time.h>
49 /* ticks left before next pre-emptive context switch */
50 int ticks_to_ctxt_switch = 0;
54 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
57 handle_tick(int unused STG_UNUSED);
59 /* -----------------------------------------------------------------------------
62 We use the ticker for two things: supporting threadDelay, and time
65 SMP note: this signal could be delivered to *any* thread. We have
66 to ensure that it doesn't matter which thread actually runs the
68 -------------------------------------------------------------------------- */
72 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
75 handle_tick(int unused STG_UNUSED)
83 /* For threadDelay etc., see Select.c */
86 ticks_to_ctxt_switch--;
87 if (ticks_to_ctxt_switch <= 0) {
88 ticks_to_ctxt_switch = RtsFlags.ConcFlags.ctxtSwitchTicks;
89 context_switch = 1; /* schedule a context switch */
95 * Handling timer events under cygwin32 is not done with signal/setitimer.
96 * Instead of the two steps of first registering a signal handler to handle
97 * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use
98 * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API
99 * creates a separate thread that will notify the main thread of timer
100 * expiry). -- SOF 7/96
102 * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
105 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
108 vtalrm_handler is assigned and set up in Signals.c
110 vtalrm_id (defined in Signals.c) holds
111 the system id for the current timer (used to
112 later block/kill it.)
114 extern nat vtalrm_id;
115 TIMECALLBACK *vtalrm_cback;
118 initialize_virtual_timer(nat ms)
121 /* On Win32 setups that don't have support for
122 setitimer(), we use the MultiMedia API's timer
125 As the delivery of ticks isn't free, we only
126 enable it if we really needed, i.e., when profiling.
127 (the RTS now also needs timer ticks to implement
128 threadDelay in non-profiling mode, but the pure
129 Win32 port doesn't support that.....yet.)
131 unsigned int delay,vtalrm_id;
133 delay = timeBeginPeriod(1);
134 if (delay == TIMERR_NOCANDO) { /* error of some sort. */
138 timeSetEvent(ms, /* event every `delay' milliseconds. */
139 1, /* precision is within 5 millisecs. */
140 (LPTIMECALLBACK)vtalrm_cback,
151 initialize_virtual_timer(nat ms)
153 # ifndef HAVE_SETITIMER
154 /* fprintf(stderr, "No virtual timer on this system\n"); */
159 it.it_value.tv_sec = ms / 1000;
160 it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
161 it.it_interval = it.it_value;
162 return (setitimer(ITIMER_VIRTUAL, &it, NULL));
166 #endif /* !cygwin32_TARGET_OS */
169 /* This is a potential POSIX version */
171 initialize_virtual_timer(nat ms)
174 struct itimerspec it;
177 se.sigev_notify = SIGEV_SIGNAL;
178 se.sigev_signo = SIGVTALRM;
179 se.sigev_value.sival_int = SIGVTALRM;
180 if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
181 barf("can't create virtual timer");
183 it.it_value.tv_sec = ms / 1000;
184 it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
185 it.it_interval = it.it_value;
186 timer_settime(tid, TIMER_RELTIME, &it, NULL);
190 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
192 install_vtalrm_handler(void)
194 vtalrm_cback = handle_tick;
200 install_vtalrm_handler(void)
202 struct sigaction action;
204 action.sa_handler = handle_tick;
206 sigemptyset(&action.sa_mask);
209 return sigaction(SIGVTALRM, &action, NULL);
213 block_vtalrm_signal(void)
217 sigemptyset(&signals);
218 sigaddset(&signals, SIGVTALRM);
220 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
224 unblock_vtalrm_signal(void)
228 sigemptyset(&signals);
229 sigaddset(&signals, SIGVTALRM);
231 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
235 #if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
237 getourtimeofday(void)
240 gettimeofday(&tv, (struct timezone *) NULL);
241 return (tv.tv_sec * 1000000 + tv.tv_usec);