[project @ 1999-12-01 14:19:36 by simonmar]
[ghc-hetmet.git] / ghc / rts / Itimer.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Itimer.c,v 1.7 1999/12/01 14:19:36 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    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
58    signal handler.
59    -------------------------------------------------------------------------- */
60
61 static void
62 handle_tick(int unused STG_UNUSED)
63 {
64   total_ticks++;
65
66 #ifdef PROFILING
67   if (do_prof_ticks = rtsTrue) {
68     CCS_TICK(CCCS);
69   }
70 #endif
71
72   /* For threadDelay etc., see Select.c */
73   ticks_since_select++;
74 }
75
76
77 /*
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
84  *
85  * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
86  */
87
88 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
89
90 /*
91   vtalrm_handler is assigned and set up in Signals.c
92
93   vtalrm_id (defined in Signals.c) holds
94   the system id for the current timer (used to 
95   later block/kill it.)
96 */
97 extern nat vtalrm_id;
98 TIMECALLBACK *vtalrm_cback;
99  
100 nat
101 initialize_virtual_timer(nat ms)
102 {
103 # ifdef PROFILING
104   /* On Win32 setups that don't have support for
105      setitimer(), we use the MultiMedia API's timer
106      support.
107      
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.)
113   */
114   unsigned int delay,vtalrm_id;
115  
116   delay = timeBeginPeriod(1);
117   if (delay == TIMERR_NOCANDO) { /* error of some sort. */
118      return delay;
119   }
120   vtalrm_id =
121     timeSetEvent(ms,     /* event every `delay' milliseconds. */
122                 1,       /* precision is within 5 millisecs. */
123                 (LPTIMECALLBACK)vtalrm_cback,
124                 0,
125                 TIME_PERIODIC);
126 # endif
127   return 0;
128 }
129  
130 #else
131
132 nat
133 initialize_virtual_timer(nat ms)
134 {
135 # ifndef HAVE_SETITIMER
136     fprintf(stderr, "No virtual timer on this system\n");
137     return -1;
138 # else
139     struct itimerval it;
140
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));
145 # endif
146 }
147
148 #endif /* !cygwin32_TARGET_OS */
149
150 # if 0
151 /* This is a potential POSIX version */
152 nat
153 initialize_virtual_timer(nat ms)
154 {
155     struct sigevent se;
156     struct itimerspec it;
157     timer_t tid;
158
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         fprintf(stderr, "Can't create virtual timer.\n");
164         EXIT(EXIT_FAILURE);
165     }
166     it.it_value.tv_sec = ms / 1000;
167     it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
168     it.it_interval = it.it_value;
169     timer_settime(tid, TIMER_RELTIME, &it, NULL);
170 }
171 # endif
172
173 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
174 int
175 install_vtalrm_handler(void)
176 {
177   vtalrm_cback = handle_tick;
178   return 0;
179 }
180
181 #else
182 int
183 install_vtalrm_handler(void)
184 {
185     struct sigaction action;
186
187     action.sa_handler = handle_tick;
188
189     sigemptyset(&action.sa_mask);
190     action.sa_flags = 0;
191
192     return sigaction(SIGVTALRM, &action, NULL);
193 }
194
195 void
196 block_vtalrm_signal(void)
197 {
198     sigset_t signals;
199     
200     sigemptyset(&signals);
201     sigaddset(&signals, SIGVTALRM);
202
203     (void) sigprocmask(SIG_BLOCK, &signals, NULL);
204 }
205
206 void
207 unblock_vtalrm_signal(void)
208 {
209     sigset_t signals;
210     
211     sigemptyset(&signals);
212     sigaddset(&signals, SIGVTALRM);
213
214     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
215 }
216 #endif