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