/* -----------------------------------------------------------------------------
*
- * (c) The GHC Team, 1995-1999
+ * (c) The GHC Team, 1995-2007
*
* Interval timer for profiling and pre-emptive scheduling.
*
*
* (1) tick in realtime. Not very good, because this ticker is used for
* profiling, and this will give us unreliable time profiling
- * results. Furthermore, this requires picking a single OS thread
- * to be the timekeeper, which is a bad idea because the thread in
- * question might just be making a temporary call into Haskell land.
+ * results.
*
* (2) save/restore the virtual timer around excursions into STG land.
* Sounds great, but I tried it and the resolution of the virtual timer
*
* For now, we're using (1), but this needs a better solution. --SDM
*/
-#ifdef THREADED_RTS
-#define ITIMER_FLAVOUR ITIMER_REAL
-#define ITIMER_SIGNAL SIGALRM
+
+#if defined(USE_TIMER_CREATE)
+
+# define ITIMER_SIGNAL SIGVTALRM
+# ifdef THREADED_RTS
+# define TIMER_FLAVOUR CLOCK_REALTIME
+# else
+# define TIMER_FLAVOUR CLOCK_PROCESS_CPUTIME_ID
+# endif
+
+#elif defined(HAVE_SETITIMER)
+
+# ifdef THREADED_RTS
+// Oh dear, we have to use SIGALRM if there's no timer_create and
+// we're using the THREADED_RTS. This leads to problems, see bug #850.
+# define ITIMER_SIGNAL SIGALRM
+# define ITIMER_FLAVOUR ITIMER_REAL
+# else
+# define ITIMER_SIGNAL SIGVTALRM
+# define ITIMER_FLAVOUR ITIMER_VIRTUAL
+# endif
+
#else
-#define ITIMER_FLAVOUR ITIMER_VIRTUAL
-#define ITIMER_SIGNAL SIGVTALRM
+
+# error No way to set an interval timer.
+
+#endif
+
+#if defined(USE_TIMER_CREATE)
+static timer_t timer;
#endif
+static nat itimer_interval = 50;
+
static
-int
+void
install_vtalrm_handler(TickProc handle_tick)
{
struct sigaction action;
action.sa_flags = 0;
#endif
- return sigaction(ITIMER_SIGNAL, &action, NULL);
+ if (sigaction(ITIMER_SIGNAL, &action, NULL) == -1) {
+ sysErrorBelch("sigaction");
+ stg_exit(EXIT_FAILURE);
+ }
}
-int
-startTicker(nat ms, TickProc handle_tick)
+void
+initTicker (nat ms, TickProc handle_tick)
{
-# ifndef HAVE_SETITIMER
- /* debugBelch("No virtual timer on this system\n"); */
- return -1;
-# else
- struct itimerval it;
-
install_vtalrm_handler(handle_tick);
#if !defined(THREADED_RTS)
timestamp = getourtimeofday();
#endif
- it.it_value.tv_sec = ms / 1000;
- it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
- it.it_interval = it.it_value;
- return (setitimer(ITIMER_FLAVOUR, &it, NULL));
-# endif
-}
+ itimer_interval = ms;
-int
-stopTicker()
-{
-# ifndef HAVE_SETITIMER
- /* debugBelch("No virtual timer on this system\n"); */
- return -1;
-# else
- struct itimerval it;
-
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = 0;
- it.it_interval = it.it_value;
- return (setitimer(ITIMER_FLAVOUR, &it, NULL));
-# endif
-}
+#if defined(USE_TIMER_CREATE)
+ {
+ struct sigevent ev;
-# if 0
-/* This is a potential POSIX version */
-int
-startTicker(nat ms)
-{
- struct sigevent se;
- struct itimerspec it;
- timer_t tid;
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = ITIMER_SIGNAL;
-#if !defined(THREADED_RTS)
- timestamp = getourtimeofday();
+ if (timer_create(TIMER_FLAVOUR, &ev, &timer) != 0) {
+ sysErrorBelch("timer_create");
+ stg_exit(EXIT_FAILURE);
+ }
+ }
#endif
+}
- se.sigev_notify = SIGEV_SIGNAL;
- se.sigev_signo = ITIMER_SIGNAL;
- se.sigev_value.sival_int = ITIMER_SIGNAL;
- if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
- barf("can't create virtual timer");
+void
+startTicker(void)
+{
+#if defined(USE_TIMER_CREATE)
+ {
+ struct itimerspec it;
+
+ it.it_value.tv_sec = itimer_interval / 1000;
+ it.it_value.tv_nsec = (itimer_interval % 1000) * 1000000;
+ it.it_interval = it.it_value;
+
+ if (timer_settime(timer, 0, &it, NULL) != 0) {
+ sysErrorBelch("timer_settime");
+ stg_exit(EXIT_FAILURE);
+ }
}
- it.it_value.tv_sec = ms / 1000;
- it.it_value.tv_nsec = 1000000 * (ms - 1000 * it.it_value.tv_sec);
- it.it_interval = it.it_value;
- return timer_settime(tid, TIMER_RELTIME, &it, NULL);
+#else
+ {
+ struct itimerval it;
+
+ it.it_value.tv_sec = itimer_interval / 1000;
+ it.it_value.tv_usec = (itimer_interval % 1000) * 1000;
+ it.it_interval = it.it_value;
+
+ if (setitimer(ITIMER_FLAVOUR, &it, NULL) != 0) {
+ sysErrorBelch("setitimer");
+ stg_exit(EXIT_FAILURE);
+ }
+ }
+#endif
}
-int
-stopTicker()
+void
+stopTicker(void)
{
- struct sigevent se;
+#if defined(USE_TIMER_CREATE)
struct itimerspec it;
- timer_t tid;
-#if !defined(THREADED_RTS)
- timestamp = getourtimeofday();
-#endif
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_nsec = 0;
+ it.it_interval = it.it_value;
- se.sigev_notify = SIGEV_SIGNAL;
- se.sigev_signo = ITIMER_SIGNAL;
- se.sigev_value.sival_int = ITIMER_SIGNAL;
- if (timer_create(CLOCK_VIRTUAL, &se, &tid)) {
- barf("can't create virtual timer");
+ if (timer_settime(timer, 0, &it, NULL) != 0) {
+ sysErrorBelch("timer_settime");
+ stg_exit(EXIT_FAILURE);
}
+#else
+ struct itimerval it;
+
it.it_value.tv_sec = 0;
- it.it_value.tv_nsec = 0;
+ it.it_value.tv_usec = 0;
it.it_interval = it.it_value;
- return timer_settime(tid, TIMER_RELTIME, &it, NULL);
+
+ if (setitimer(ITIMER_FLAVOUR, &it, NULL) != 0) {
+ sysErrorBelch("setitimer");
+ stg_exit(EXIT_FAILURE);
+ }
+#endif
+}
+
+void
+exitTicker(void)
+{
+#if defined(USE_TIMER_CREATE)
+ timer_delete(timer);
+ // ignore errors - we don't really care if it fails.
+#endif
}
-# endif
#if 0
/* Currently unused */
getourtimeofday(void)
{
struct timeval tv;
+ nat interval;
+ interval = RtsFlags.MiscFlags.tickInterval;
+ if (interval == 0) { interval = 50; }
gettimeofday(&tv, (struct timezone *) NULL);
// cast to lnat because nat may be 64 bit when int is only 32 bit
- return ((lnat)tv.tv_sec * 1000 / RtsFlags.MiscFlags.tickInterval +
- (lnat)tv.tv_usec / (RtsFlags.MiscFlags.tickInterval * 1000));
+ return ((lnat)tv.tv_sec * 1000 / interval +
+ (lnat)tv.tv_usec / (interval * 1000));
}