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