1 /* -----------------------------------------------------------------------------
2 * $Id: Itimer.c,v 1.14 2000/06/20 15:12:14 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
27 #include "Proftimer.h"
30 /* As recommended in the autoconf manual */
31 # ifdef TIME_WITH_SYS_TIME
32 # include <sys/time.h>
35 # ifdef HAVE_SYS_TIME_H
36 # include <sys/time.h>
50 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
53 handle_tick(int unused STG_UNUSED);
55 /* -----------------------------------------------------------------------------
58 We use the ticker for two things: supporting threadDelay, and time
61 SMP note: this signal could be delivered to *any* thread. We have
62 to ensure that it doesn't matter which thread actually runs the
64 -------------------------------------------------------------------------- */
68 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
71 handle_tick(int unused STG_UNUSED)
79 /* For threadDelay etc., see Select.c */
87 * Handling timer events under cygwin32 is not done with signal/setitimer.
88 * Instead of the two steps of first registering a signal handler to handle
89 * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use
90 * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API
91 * creates a separate thread that will notify the main thread of timer
92 * expiry). -- SOF 7/96
94 * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
97 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
100 * Sigh - to avoid requiring anyone that wants to build ghc to have
101 * to augment the Win32 header files that comes with cygwinb20.1,
102 * include the missing MM API decls here inline.
104 * ToDo: check and remove these once the next version of cygwin is
107 #define TIMERR_NOERROR 0
108 #define TIMERR_NOCANDO 97
109 #define TIME_PERIODIC 1
111 typedef UINT MMRESULT;
112 typedef void CALLBACK (*TIMECALLBACK) (UINT, UINT, DWORD, DWORD, DWORD);
113 typedef TIMECALLBACK *LPTIMECALLBACK;
114 MMRESULT STDCALL timeSetEvent(UINT, UINT, LPTIMECALLBACK, DWORD, UINT);
116 vtalrm_handler is assigned and set up in Signals.c
118 vtalrm_id (defined in Signals.c) holds
119 the system id for the current timer (used to
120 later block/kill it.)
122 extern nat vtalrm_id;
123 TIMECALLBACK *vtalrm_cback;
126 initialize_virtual_timer(nat ms)
129 /* On Win32 setups that don't have support for
130 setitimer(), we use the MultiMedia API's timer
133 As the delivery of ticks isn't free, we only
134 enable it if we really needed, i.e., when profiling.
135 (the RTS now also needs timer ticks to implement
136 threadDelay in non-profiling mode, but the pure
137 Win32 port doesn't support that.....yet.)
139 unsigned int delay,vtalrm_id;
141 delay = timeBeginPeriod(1);
142 if (delay == TIMERR_NOCANDO) { /* error of some sort. */
146 timeSetEvent(ms, /* event every `delay' milliseconds. */
147 1, /* precision is within 5 millisecs. */
148 (LPTIMECALLBACK)vtalrm_cback,
158 initialize_virtual_timer(nat ms)
160 # ifndef HAVE_SETITIMER
161 /* fprintf(stderr, "No virtual timer on this system\n"); */
166 it.it_value.tv_sec = ms / 1000;
167 it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
168 it.it_interval = it.it_value;
169 return (setitimer(ITIMER_VIRTUAL, &it, NULL));
173 #endif /* !cygwin32_TARGET_OS */
176 /* This is a potential POSIX version */
178 initialize_virtual_timer(nat ms)
181 struct itimerspec it;
184 se.sigev_notify = SIGEV_SIGNAL;
185 se.sigev_signo = SIGVTALRM;
186 se.sigev_value.sival_int = SIGVTALRM;
187 if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
188 barf("can't create virtual timer");
190 it.it_value.tv_sec = ms / 1000;
191 it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
192 it.it_interval = it.it_value;
193 timer_settime(tid, TIMER_RELTIME, &it, NULL);
197 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
199 install_vtalrm_handler(void)
201 vtalrm_cback = handle_tick;
207 install_vtalrm_handler(void)
209 struct sigaction action;
211 action.sa_handler = handle_tick;
213 sigemptyset(&action.sa_mask);
216 return sigaction(SIGVTALRM, &action, NULL);
220 block_vtalrm_signal(void)
224 sigemptyset(&signals);
225 sigaddset(&signals, SIGVTALRM);
227 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
231 unblock_vtalrm_signal(void)
235 sigemptyset(&signals);
236 sigaddset(&signals, SIGVTALRM);
238 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
242 #if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
244 getourtimeofday(void)
247 gettimeofday(&tv, (struct timezone *) NULL);
248 return (tv.tv_sec * 1000000 + tv.tv_usec);