Use timer_create() for the interval timer, if available
authorSimon Marlow <simonmar@microsoft.com>
Fri, 2 Mar 2007 11:31:04 +0000 (11:31 +0000)
committerSimon Marlow <simonmar@microsoft.com>
Fri, 2 Mar 2007 11:31:04 +0000 (11:31 +0000)
This lets the threaded RTS use SIGVTALRM rather than SIGALRM for its
interval timer signal, so the threaded and non-threaded RTS are
compatible.  It unfortunately doesn't completely fix #850/#1156, for
that we really have to use a restartable sleep instead of usleep().

Also I cleaned up the timer API a little: instead of returning an
error value that ultimately gets ignored, we now report errors from
system calls and exit.

configure.ac
rts/Ticker.h
rts/Timer.c
rts/Timer.h
rts/posix/Itimer.c
rts/win32/Ticker.c

index 8cf4d61..fbb9d29 100644 (file)
@@ -1196,7 +1196,7 @@ AC_COMPILE_IFELSE(
 
 dnl ** check for librt
 AC_CHECK_LIB(rt, clock_gettime)
-AC_CHECK_FUNCS(clock_gettime)
+AC_CHECK_FUNCS(clock_gettime timer_create timer_settime)
 
 dnl ** check for Apple's "interesting" long double compatibility scheme
 AC_MSG_CHECKING(for printf\$LDBLStub)
index f955576..b06890a 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef TICKER_H
 #define TICKER_H
 
-extern int  startTicker( nat ms, TickProc handle_tick );
-extern int  stopTicker ( void );
+extern void startTicker( nat ms, TickProc handle_tick );
+extern void stopTicker ( void );
 
 #endif /* TICKER_H */
index 8088600..493fe3d 100644 (file)
@@ -83,18 +83,18 @@ handle_tick(int unused STG_UNUSED)
 #endif
 }
 
-int
+void
 startTimer(void)
 {
 #ifdef PROFILING
   initProfTimer();
 #endif
 
-  return startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
+  startTicker(RtsFlags.MiscFlags.tickInterval, handle_tick);
 }
 
-int
+void
 stopTimer(void)
 {
-  return stopTicker();
+  stopTicker();
 }
index 1fe857d..6d3c415 100644 (file)
@@ -11,7 +11,7 @@
 
 typedef void (*TickProc)(int);
 
-extern int startTimer(void);
-extern int stopTimer(void);
+extern void startTimer(void);
+extern void stopTimer(void);
 
 #endif /* TIMER_H */
index 715cf5a..8600c0a 100644 (file)
@@ -52,9 +52,7 @@
  *
  * (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(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
+
+#  define 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)
+
+#  define USE_ITIMER
+#  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)
+timer_t timer;
 #endif
 
 static
-int
+void
 install_vtalrm_handler(TickProc handle_tick)
 {
     struct sigaction action;
@@ -98,95 +122,86 @@ install_vtalrm_handler(TickProc handle_tick)
     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
+void
 startTicker(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
-}
-
-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 0
-/* This is a potential POSIX version */
-int
-startTicker(nat ms)
-{
-    struct sigevent se;
-    struct itimerspec it;
-    timer_t tid;
-
-#if !defined(THREADED_RTS)
-    timestamp = getourtimeofday();
-#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");
+#if defined(USE_TIMER_CREATE)
+    {
+        struct itimerspec it;
+        struct sigevent ev;
+
+        ev.sigev_notify = SIGEV_SIGNAL;
+        ev.sigev_signo  = ITIMER_SIGNAL;
+        
+        it.it_value.tv_sec = ms / 1000;
+        it.it_value.tv_nsec = (ms % 1000) * 1000000;
+        it.it_interval = it.it_value;
+        
+        if (timer_create(TIMER_FLAVOUR, &ev, &timer) != 0) {
+            sysErrorBelch("timer_create");
+            stg_exit(EXIT_FAILURE);
+        }
+
+        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 = ms / 1000;
+        it.it_value.tv_usec = (ms % 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
 }
-# endif
 
 #if 0
 /* Currently unused */
index 7701a3b..5b41494 100644 (file)
@@ -74,7 +74,7 @@ TimerProc(PVOID param)
 }
 
 
-int
+void
 startTicker(nat ms, TickProc handle_tick)
 {
   unsigned threadId;
@@ -95,10 +95,14 @@ startTicker(nat ms, TickProc handle_tick)
                               (LPVOID)ms,
                               0,
                               &threadId);
-  return (tickThread != 0);
+
+  if (tickThread == 0) {
+      sysErrorBelch("_beginthreadex");
+      stg_exit(EXIT_FAILURE);
+  }
 }
 
-int
+void
 stopTicker(void)
 {
     // We must wait for the ticker thread to terminate, since if we
@@ -125,5 +129,4 @@ stopTicker(void)
            TerminateThread(tickThread, 0);
        }
     }
-    return 0;
 }