9117157a165fcf35f9ebeefb7c87e491e7314214
[ghc-hetmet.git] / ghc / rts / Itimer.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Itimer.c,v 1.15 2000/07/17 15:09:35 rrt 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 "Proftimer.h"
28 #include "Schedule.h"
29
30 /* As recommended in the autoconf manual */
31 # ifdef TIME_WITH_SYS_TIME
32 #  include <sys/time.h>
33 #  include <time.h>
34 # else
35 #  ifdef HAVE_SYS_TIME_H
36 #   include <sys/time.h>
37 #  else
38 #   include <time.h>
39 #  endif
40 # endif
41
42 #if HAVE_WINDOWS_H
43 # include <windows.h>
44 #endif
45  
46 lnat total_ticks = 0;
47
48 static
49 void
50 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
51 CALLBACK
52 #endif
53 handle_tick(int unused STG_UNUSED);
54
55 /* -----------------------------------------------------------------------------
56    Tick handler
57
58    We use the ticker for two things: supporting threadDelay, and time
59    profiling.
60
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
63    signal handler.
64    -------------------------------------------------------------------------- */
65
66 static
67 void
68 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
69 CALLBACK
70 #endif
71 handle_tick(int unused STG_UNUSED)
72 {
73   total_ticks++;
74
75 #ifdef PROFILING
76   handleProfTick();
77 #endif
78
79   /* For threadDelay etc., see Select.c */
80   ticks_since_select++;
81
82   context_switch = 1;
83 }
84
85
86 /*
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
93  *
94  * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
95  */
96
97 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
98
99 /*
100   vtalrm_handler is assigned and set up in Signals.c
101
102   vtalrm_id (defined in Signals.c) holds
103   the system id for the current timer (used to 
104   later block/kill it.)
105 */
106 extern nat vtalrm_id;
107 TIMECALLBACK *vtalrm_cback;
108  
109 nat
110 initialize_virtual_timer(nat ms)
111 {
112 # ifdef PROFILING
113   /* On Win32 setups that don't have support for
114      setitimer(), we use the MultiMedia API's timer
115      support.
116      
117      As the delivery of ticks isn't free, we only
118      enable it if we really needed, i.e., when profiling.
119      (the RTS now also needs timer ticks to implement
120      threadDelay in non-profiling mode, but the pure
121      Win32 port doesn't support that.....yet.)
122   */
123   unsigned int delay,vtalrm_id;
124  
125   delay = timeBeginPeriod(1);
126   if (delay == TIMERR_NOCANDO) { /* error of some sort. */
127      return delay;
128   }
129   vtalrm_id =
130     timeSetEvent(ms,     /* event every `delay' milliseconds. */
131                 1,       /* precision is within 5 millisecs. */
132                 (LPTIMECALLBACK)vtalrm_cback,
133                 0,
134                 TIME_PERIODIC);
135 # endif
136   return 0;
137 }
138  
139 #else
140
141 nat
142 initialize_virtual_timer(nat ms)
143 {
144 # ifndef HAVE_SETITIMER
145   /*    fprintf(stderr, "No virtual timer on this system\n"); */
146     return -1;
147 # else
148     struct itimerval it;
149
150     it.it_value.tv_sec = ms / 1000;
151     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
152     it.it_interval = it.it_value;
153     return (setitimer(ITIMER_VIRTUAL, &it, NULL));
154 # endif
155 }
156
157 #endif /* !cygwin32_TARGET_OS */
158
159 # if 0
160 /* This is a potential POSIX version */
161 nat
162 initialize_virtual_timer(nat ms)
163 {
164     struct sigevent se;
165     struct itimerspec it;
166     timer_t tid;
167
168     se.sigev_notify = SIGEV_SIGNAL;
169     se.sigev_signo = SIGVTALRM;
170     se.sigev_value.sival_int = SIGVTALRM;
171     if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
172         barf("can't create virtual timer");
173     }
174     it.it_value.tv_sec = ms / 1000;
175     it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
176     it.it_interval = it.it_value;
177     timer_settime(tid, TIMER_RELTIME, &it, NULL);
178 }
179 # endif
180
181 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
182 int
183 install_vtalrm_handler(void)
184 {
185   vtalrm_cback = handle_tick;
186   return 0;
187 }
188
189 #else
190 int
191 install_vtalrm_handler(void)
192 {
193     struct sigaction action;
194
195     action.sa_handler = handle_tick;
196
197     sigemptyset(&action.sa_mask);
198     action.sa_flags = 0;
199
200     return sigaction(SIGVTALRM, &action, NULL);
201 }
202
203 void
204 block_vtalrm_signal(void)
205 {
206     sigset_t signals;
207     
208     sigemptyset(&signals);
209     sigaddset(&signals, SIGVTALRM);
210
211     (void) sigprocmask(SIG_BLOCK, &signals, NULL);
212 }
213
214 void
215 unblock_vtalrm_signal(void)
216 {
217     sigset_t signals;
218     
219     sigemptyset(&signals);
220     sigaddset(&signals, SIGVTALRM);
221
222     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
223 }
224 #endif
225
226 #if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
227 unsigned int 
228 getourtimeofday(void)
229 {
230   struct timeval tv;
231   gettimeofday(&tv, (struct timezone *) NULL);
232   return (tv.tv_sec * 1000000 + tv.tv_usec);
233 }
234 #endif