[project @ 1999-08-25 16:11:43 by simonmar]
[ghc-hetmet.git] / ghc / rts / Itimer.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Itimer.c,v 1.5 1999/08/25 16:11:48 simonmar Exp $
3  *
4  * (c) The GHC Team, 1995-1999
5  *
6  * Interval timer for profiling and pre-emptive scheduling.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 /*
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@.
16  * 
17  * Hence, we use the old-fashioned @setitimer@ that just about everyone seems
18  * to support.  So much for standards.
19  */
20
21 #if !defined(_AIX)
22 # define NON_POSIX_SOURCE
23 #endif
24
25 #include "Rts.h"
26 #include "Itimer.h"
27 #include "Schedule.h"
28
29 /* As recommended in the autoconf manual */
30 # ifdef TIME_WITH_SYS_TIME
31 #  include <sys/time.h>
32 #  include <time.h>
33 # else
34 #  ifdef HAVE_SYS_TIME_H
35 #   include <sys/time.h>
36 #  else
37 #   include <time.h>
38 #  endif
39 # endif
40
41 #if HAVE_WINDOWS_H
42 # include <windows.h>
43 #endif
44  
45 lnat total_ticks = 0;
46 rtsBool do_prof_ticks = rtsFalse;
47
48 static void handle_tick(int unused STG_UNUSED);
49
50 /* -----------------------------------------------------------------------------
51    Tick handler
52
53    We use the ticker for two things: supporting threadDelay, and time
54    profiling.
55    -------------------------------------------------------------------------- */
56
57 static void
58 handle_tick(int unused STG_UNUSED)
59 {
60   total_ticks++;
61
62 #ifdef PROFILING
63   if (do_prof_ticks = rtsTrue) {
64     CCS_TICK(CCCS);
65   }
66 #endif
67
68   /* For threadDelay etc., see Select.c */
69   ticks_since_select++;
70 }
71
72
73 /*
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
80  *
81  * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
82  */
83
84 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
85
86 /*
87   vtalrm_handler is assigned and set up in Signals.c
88
89   vtalrm_id (defined in Signals.c) holds
90   the system id for the current timer (used to 
91   later block/kill it.)
92 */
93 extern nat vtalrm_id;
94 TIMECALLBACK *vtalrm_cback;
95  
96 nat
97 initialize_virtual_timer(nat ms)
98 {
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.
103   */
104   unsigned int delay,vtalrm_id;
105  
106   delay = timeBeginPeriod(1);
107   if (delay == TIMERR_NOCANDO) { /* error of some sort. */
108      return delay;
109   }
110   vtalrm_id =
111     timeSetEvent(ms,     /* event every `delay' milliseconds. */
112                 1,       /* precision is within 5 millisecs. */
113                 (LPTIMECALLBACK)vtalrm_cback,
114                 0,
115                 TIME_PERIODIC);
116   return 0;
117 }
118  
119 #else
120
121 nat
122 initialize_virtual_timer(nat ms)
123 {
124 # ifndef HAVE_SETITIMER
125     fprintf(stderr, "No virtual timer on this system\n");
126     return -1;
127 # else
128     struct itimerval it;
129
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));
134 # endif
135 }
136
137 #endif /* !cygwin32_TARGET_OS */
138
139 # if 0
140 /* This is a potential POSIX version */
141 nat
142 initialize_virtual_timer(nat ms)
143 {
144     struct sigevent se;
145     struct itimerspec it;
146     timer_t tid;
147
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");
153         EXIT(EXIT_FAILURE);
154     }
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);
159 }
160 # endif
161
162 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
163 int
164 install_vtalrm_handler(void)
165 {
166   vtalrm_cback = handle_tick;
167   return 0;
168 }
169
170 #else
171 int
172 install_vtalrm_handler(void)
173 {
174     struct sigaction action;
175
176     action.sa_handler = handle_tick;
177
178     sigemptyset(&action.sa_mask);
179     action.sa_flags = 0;
180
181     return sigaction(SIGVTALRM, &action, NULL);
182 }
183
184 void
185 block_vtalrm_signal(void)
186 {
187     sigset_t signals;
188     
189     sigemptyset(&signals);
190     sigaddset(&signals, SIGVTALRM);
191
192     (void) sigprocmask(SIG_BLOCK, &signals, NULL);
193 }
194
195 void
196 unblock_vtalrm_signal(void)
197 {
198     sigset_t signals;
199     
200     sigemptyset(&signals);
201     sigaddset(&signals, SIGVTALRM);
202
203     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
204 }
205 #endif