Signals: Ensure libdw session is freed
[ghc.git] / rts / posix / Itimer.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 1995-2007
4 *
5 * Interval timer for profiling and pre-emptive scheduling.
6 *
7 * ---------------------------------------------------------------------------*/
8
9 /*
10 * The interval timer is used for profiling and for context switching in the
11 * threaded build. Though POSIX 1003.1b includes a standard interface for
12 * such things, no one really seems to be implementing them yet. Even
13 * Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
14 * keen on getting access to @CLOCK_VIRTUAL@.
15 *
16 * Hence, we use the old-fashioned @setitimer@ that just about everyone seems
17 * to support. So much for standards.
18 */
19
20 #include "PosixSource.h"
21 #include "Rts.h"
22
23 #include "Ticker.h"
24 #include "Itimer.h"
25 #include "Proftimer.h"
26 #include "Schedule.h"
27 #include "Clock.h"
28
29 /* As recommended in the autoconf manual */
30 # ifdef TIME_WITH_SYS_TIME
31 # include <sys/time.h>
32 # include <time.h>
33 # else
34 # ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 # else
37 # include <time.h>
38 # endif
39 # endif
40
41 #ifdef HAVE_SIGNAL_H
42 # include <signal.h>
43 #endif
44
45 #include <string.h>
46
47 /*
48 * timer_create doesn't exist and setitimer doesn't fire on iOS, so we're using
49 * a pthreads-based implementation. It may be to do with interference with the
50 * signals of the debugger. Revisit. See #7723.
51 */
52 #if defined(ios_HOST_OS)
53 #define USE_PTHREAD_FOR_ITIMER
54 #endif
55
56 #if defined(USE_PTHREAD_FOR_ITIMER)
57 #include <pthread.h>
58 #include <unistd.h>
59 #endif
60
61 /*
62 * We use a realtime timer by default. I found this much more
63 * reliable than a CPU timer:
64 *
65 * Experiments with different frequences: using
66 * CLOCK_REALTIME/CLOCK_MONOTONIC on Linux 2.6.32,
67 * 1000us has <1% impact on runtime
68 * 100us has ~2% impact on runtime
69 * 10us has ~40% impact on runtime
70 *
71 * using CLOCK_PROCESS_CPUTIME_ID on Linux 2.6.32,
72 * I cannot get it to tick faster than 10ms (10000us)
73 * which isn't great for profiling.
74 *
75 * In the threaded RTS, we can't tick in CPU time because the thread
76 * which has the virtual timer might be idle, so the tick would never
77 * fire. Therfore we used to tick in realtime in the threaded RTS and
78 * in CPU time otherwise, but now we always tick in realtime, for
79 * several reasons:
80 *
81 * - resolution (see above)
82 * - consistency (-threaded is the same as normal)
83 * - more consistency: Windows only has a realtime timer
84 *
85 * Note we want to use CLOCK_MONOTONIC rather than CLOCK_REALTIME,
86 * because the latter may jump around (NTP adjustments, leap seconds
87 * etc.).
88 */
89
90 #if defined(solaris2_HOST_OS)
91 /* USE_TIMER_CREATE is usually disabled for Solaris. In fact it is
92 supported well on this OS, but requires additional privilege. When
93 user does not have it, then the testing configure program fails
94 which results in USE_TIMER_CREATE not defined.
95 On the other hand when we cross-compile, then we optimistically
96 assume usage of timer_create function. The problem is that if we
97 cross compile for example from i386-solaris2 to x86_64-solaris2,
98 then the build fails with error like this:
99
100 ghc-stage2: timer_create: Not owner
101
102 which happens on first ghc-stage2 invocation. So to support
103 cross-compilation to Solaris we manually undefine USE_TIMER_CREATE
104 here */
105 #undef USE_TIMER_CREATE
106 #endif /* solaris2_HOST_OS */
107
108 #if defined(USE_TIMER_CREATE)
109 # define ITIMER_SIGNAL SIGVTALRM
110 #elif defined(HAVE_SETITIMER)
111 # define ITIMER_SIGNAL SIGALRM
112 // Using SIGALRM can leads to problems, see #850. But we have no
113 // option if timer_create() is not available.
114 #else
115 # error No way to set an interval timer.
116 #endif
117
118 #if defined(USE_TIMER_CREATE)
119 static timer_t timer;
120 #endif
121
122 static Time itimer_interval = DEFAULT_TICK_INTERVAL;
123
124 #if !defined(USE_PTHREAD_FOR_ITIMER)
125 static void install_vtalrm_handler(TickProc handle_tick)
126 {
127 struct sigaction action;
128
129 action.sa_handler = handle_tick;
130
131 sigemptyset(&action.sa_mask);
132
133 #ifdef SA_RESTART
134 // specify SA_RESTART. One consequence if we don't do this is
135 // that readline gets confused by the -threaded RTS. It seems
136 // that if a SIGALRM handler is installed without SA_RESTART,
137 // readline installs its own SIGALRM signal handler (see
138 // readline's signals.c), and this somehow causes readline to go
139 // wrong when the input exceeds a single line (try it).
140 action.sa_flags = SA_RESTART;
141 #else
142 action.sa_flags = 0;
143 #endif
144
145 if (sigaction(ITIMER_SIGNAL, &action, NULL) == -1) {
146 sysErrorBelch("sigaction");
147 stg_exit(EXIT_FAILURE);
148 }
149 }
150 #endif
151
152 #if defined(USE_PTHREAD_FOR_ITIMER)
153 static volatile int itimer_enabled;
154 static void *itimer_thread_func(void *_handle_tick)
155 {
156 TickProc handle_tick = _handle_tick;
157 while (1) {
158 usleep(TimeToUS(itimer_interval));
159 switch (itimer_enabled) {
160 case 1: handle_tick(0); break;
161 case 2: itimer_enabled = 0;
162 }
163 }
164 return NULL;
165 }
166 #endif
167
168 void
169 initTicker (Time interval, TickProc handle_tick)
170 {
171 itimer_interval = interval;
172
173 #if defined(USE_PTHREAD_FOR_ITIMER)
174 pthread_t tid;
175 pthread_create(&tid, NULL, itimer_thread_func, (void*)handle_tick);
176 #elif defined(USE_TIMER_CREATE)
177 {
178 struct sigevent ev;
179
180 // Keep programs like valgrind happy
181 memset(&ev, 0, sizeof(ev));
182
183 ev.sigev_notify = SIGEV_SIGNAL;
184 ev.sigev_signo = ITIMER_SIGNAL;
185
186 if (timer_create(CLOCK_ID, &ev, &timer) != 0) {
187 sysErrorBelch("timer_create");
188 stg_exit(EXIT_FAILURE);
189 }
190 }
191 install_vtalrm_handler(handle_tick);
192 #else
193 install_vtalrm_handler(handle_tick);
194 #endif
195 }
196
197 void
198 startTicker(void)
199 {
200 #if defined(USE_PTHREAD_FOR_ITIMER)
201 itimer_enabled = 1;
202 #elif defined(USE_TIMER_CREATE)
203 {
204 struct itimerspec it;
205
206 it.it_value.tv_sec = TimeToSeconds(itimer_interval);
207 it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
208 it.it_interval = it.it_value;
209
210 if (timer_settime(timer, 0, &it, NULL) != 0) {
211 sysErrorBelch("timer_settime");
212 stg_exit(EXIT_FAILURE);
213 }
214 }
215 #else
216 {
217 struct itimerval it;
218
219 it.it_value.tv_sec = TimeToSeconds(itimer_interval);
220 it.it_value.tv_usec = TimeToUS(itimer_interval) % 1000000;
221 it.it_interval = it.it_value;
222
223 if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
224 sysErrorBelch("setitimer");
225 stg_exit(EXIT_FAILURE);
226 }
227 }
228 #endif
229 }
230
231 void
232 stopTicker(void)
233 {
234 #if defined(USE_PTHREAD_FOR_ITIMER)
235 if (itimer_enabled == 1) {
236 itimer_enabled = 2;
237 /* Wait for the thread to confirm it won't generate another tick. */
238 while (itimer_enabled != 0)
239 sched_yield();
240 }
241 #elif defined(USE_TIMER_CREATE)
242 struct itimerspec it;
243
244 it.it_value.tv_sec = 0;
245 it.it_value.tv_nsec = 0;
246 it.it_interval = it.it_value;
247
248 if (timer_settime(timer, 0, &it, NULL) != 0) {
249 sysErrorBelch("timer_settime");
250 stg_exit(EXIT_FAILURE);
251 }
252 #else
253 struct itimerval it;
254
255 it.it_value.tv_sec = 0;
256 it.it_value.tv_usec = 0;
257 it.it_interval = it.it_value;
258
259 if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
260 sysErrorBelch("setitimer");
261 stg_exit(EXIT_FAILURE);
262 }
263 #endif
264 }
265
266 void
267 exitTicker (rtsBool wait STG_UNUSED)
268 {
269 #if defined(USE_TIMER_CREATE)
270 // Before deleting the timer set the signal to ignore to avoid the
271 // possibility of the signal being delivered after the timer is deleted.
272 signal(ITIMER_SIGNAL, SIG_IGN);
273 timer_delete(timer);
274 // ignore errors - we don't really care if it fails.
275 #endif
276 }
277
278 int
279 rtsTimerSignal(void)
280 {
281 return ITIMER_SIGNAL;
282 }