[project @ 2003-03-26 02:12:38 by sof]
[ghc-hetmet.git] / ghc / rts / Itimer.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Itimer.c,v 1.32 2003/02/22 04:51:50 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 #include "Rts.h"
21 #if !defined(mingw32_TARGET_OS) /* to the end */
22 #include "RtsFlags.h"
23 #include "Timer.h"
24 #include "Itimer.h"
25 #include "Proftimer.h"
26 #include "Schedule.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 #ifdef HAVE_SIGNAL_H
41 # include <signal.h>
42 #endif
43
44 static
45 int
46 install_vtalrm_handler(void)
47 {
48     struct sigaction action;
49
50     action.sa_handler = handle_tick;
51
52     sigemptyset(&action.sa_mask);
53     action.sa_flags = 0;
54
55     return sigaction(SIGVTALRM, &action, NULL);
56 }
57
58 int
59 startTicker(nat ms)
60 {
61 # ifndef HAVE_SETITIMER
62   /*    fprintf(stderr, "No virtual timer on this system\n"); */
63     return -1;
64 # else
65     struct itimerval it;
66
67     install_vtalrm_handler();
68
69     timestamp = getourtimeofday();
70
71     it.it_value.tv_sec = ms / 1000;
72     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
73     it.it_interval = it.it_value;
74     return (setitimer(ITIMER_VIRTUAL, &it, NULL));
75 # endif
76 }
77
78 int
79 stopTicker()
80 {
81 # ifndef HAVE_SETITIMER
82   /*    fprintf(stderr, "No virtual timer on this system\n"); */
83     return -1;
84 # else
85     struct itimerval it;
86   
87     it.it_value.tv_sec = 0;
88     it.it_value.tv_usec = 0;
89     it.it_interval = it.it_value;
90     return (setitimer(ITIMER_VIRTUAL, &it, NULL));
91 # endif
92 }
93
94 # if 0
95 /* This is a potential POSIX version */
96 int
97 startTicker(nat ms)
98 {
99     struct sigevent se;
100     struct itimerspec it;
101     timer_t tid;
102
103     timestamp = getourtimeofday();
104
105     se.sigev_notify = SIGEV_SIGNAL;
106     se.sigev_signo = SIGVTALRM;
107     se.sigev_value.sival_int = SIGVTALRM;
108     if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
109         barf("can't create virtual timer");
110     }
111     it.it_value.tv_sec = ms / 1000;
112     it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
113     it.it_interval = it.it_value;
114     return timer_settime(tid, TIMER_RELTIME, &it, NULL);
115 }
116
117 int
118 stopTicker()
119 {
120     struct sigevent se;
121     struct itimerspec it;
122     timer_t tid;
123
124     timestamp = getourtimeofday();
125
126     se.sigev_notify = SIGEV_SIGNAL;
127     se.sigev_signo = SIGVTALRM;
128     se.sigev_value.sival_int = SIGVTALRM;
129     if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
130         barf("can't create virtual timer");
131     }
132     it.it_value.tv_sec = 0;
133     it.it_value.tv_nsec = 0;
134     it.it_interval = it.it_value;
135     return timer_settime(tid, TIMER_RELTIME, &it, NULL);
136 }
137 # endif
138
139 void
140 block_vtalrm_signal(void)
141 {
142     sigset_t signals;
143     
144     sigemptyset(&signals);
145     sigaddset(&signals, SIGVTALRM);
146
147     (void) sigprocmask(SIG_BLOCK, &signals, NULL);
148 }
149
150 void
151 unblock_vtalrm_signal(void)
152 {
153     sigset_t signals;
154     
155     sigemptyset(&signals);
156     sigaddset(&signals, SIGVTALRM);
157
158     (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
159 }
160
161 /* gettimeofday() takes around 1us on our 500MHz PIII.  Since we're
162  * only calling it 50 times/s, it shouldn't have any great impact.
163  */
164 unsigned int 
165 getourtimeofday(void)
166 {
167   struct timeval tv;
168   gettimeofday(&tv, (struct timezone *) NULL);
169   return (tv.tv_sec * TICK_FREQUENCY +
170           tv.tv_usec * TICK_FREQUENCY / 1000000);
171 }
172
173 #endif /* !mingw32_TARGET_OS */