[project @ 1999-03-03 19:00:07 by sof]
[ghc-hetmet.git] / ghc / rts / Itimer.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Itimer.c,v 1.4 1999/03/03 19:00:07 sof 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
28 /* As recommended in the autoconf manual */
29 # ifdef TIME_WITH_SYS_TIME
30 #  include <sys/time.h>
31 #  include <time.h>
32 # else
33 #  ifdef HAVE_SYS_TIME_H
34 #   include <sys/time.h>
35 #  else
36 #   include <time.h>
37 #  endif
38 # endif
39
40 #if HAVE_WINDOWS_H
41 # include <windows.h>
42 #endif
43  
44 /*
45  * Handling timer events under cygwin32 is not done with signal/setitimer.
46  * Instead of the two steps of first registering a signal handler to handle
47  * \tr{SIGVTALRM} and then start generating them via @setitimer()@, we use
48  * the Multimedia API (MM) and its @timeSetEvent@. (Internally, the MM API
49  * creates a separate thread that will notify the main thread of timer
50  * expiry). -- SOF 7/96
51  *
52  * 11/98: if the cygwin DLL supports setitimer(), then use it instead.
53  */
54
55 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
56
57 /*
58   vtalrm_handler is assigned and set up in Signals.c
59
60   vtalrm_id (defined in Signals.c) holds
61   the system id for the current timer (used to 
62   later block/kill it.)
63 */
64 extern nat vtalrm_id;
65 TIMECALLBACK *vtalrm_cback;
66  
67 nat
68 initialize_virtual_timer(nat ms)
69 {
70   /* VTALRM is currently not supported by  cygwin32, 
71      so we use the Timer support provided by the
72      MultiMedia API that is part of Win32. The
73      parameters to timeSetEvent may require some tweaking.
74   */
75   unsigned int delay,vtalrm_id;
76  
77   delay = timeBeginPeriod(1);
78   if (delay == TIMERR_NOCANDO) { /* error of some sort. */
79      return delay;
80   }
81   vtalrm_id =
82     timeSetEvent(ms,     /* event every `delay' milliseconds. */
83                 1,       /* precision is within 5 millisecs. */
84                 (LPTIMECALLBACK)vtalrm_cback,
85                 0,
86                 TIME_PERIODIC);
87   return 0;
88 }
89  
90 #else
91
92 nat
93 initialize_virtual_timer(nat ms)
94 {
95 # ifndef HAVE_SETITIMER
96     fprintf(stderr, "No virtual timer on this system\n");
97     return -1;
98 # else
99     struct itimerval it;
100
101     it.it_value.tv_sec = ms / 1000;
102     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
103     it.it_interval = it.it_value;
104     return (setitimer(ITIMER_VIRTUAL, &it, NULL));
105 # endif
106 }
107
108 #endif /* !cygwin32_TARGET_OS */
109
110 # if 0
111 /* This is a potential POSIX version */
112 nat
113 initialize_virtual_timer(nat ms)
114 {
115     struct sigevent se;
116     struct itimerspec it;
117     timer_t tid;
118
119     se.sigev_notify = SIGEV_SIGNAL;
120     se.sigev_signo = SIGVTALRM;
121     se.sigev_value.sival_int = SIGVTALRM;
122     if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
123         fprintf(stderr, "Can't create virtual timer.\n");
124         EXIT(EXIT_FAILURE);
125     }
126     it.it_value.tv_sec = ms / 1000;
127     it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
128     it.it_interval = it.it_value;
129     timer_settime(tid, TIMER_RELTIME, &it, NULL);
130 }
131 # endif
132
133 #if defined(mingw32_TARGET_OS) || (defined(cygwin32_TARGET_OS) && !defined(HAVE_SETITIMER))
134 int
135 install_vtalrm_handler(void (*handler)(int))
136 {
137   vtalrm_cback = handler;
138   return 0;
139 }
140
141 #else
142 int
143 install_vtalrm_handler(void (*handler)(int))
144 {
145     struct sigaction action;
146
147     action.sa_handler = handler;
148
149     sigemptyset(&action.sa_mask);
150     action.sa_flags = 0;
151
152     return sigaction(SIGVTALRM, &action, NULL);
153 }
154
155 void
156 block_vtalrm_signal(void)
157 {
158     sigset_t signals;
159     
160     sigemptyset(&signals);
161     sigaddset(&signals, SIGVTALRM);
162
163     (void) sigprocmask(SIG_BLOCK, &signals, NULL);
164 }
165
166 void
167 unblock_vtalrm_signal(void)
168 {
169     sigset_t signals;
170     
171     sigemptyset(&signals);
172     sigaddset(&signals, SIGVTALRM);
173
174     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
175 }
176 #endif