summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2016-05-01 13:39:23 +0200
committerBen Gamari <ben@smart-cactus.org>2016-05-01 23:29:49 +0200
commit65e13f66c595ad75bd6e9a55496f1372ead2731d (patch)
tree91155c792ab9eda72f24c712e6c4e2641514451f
parent16a51a6c2f265f8670355be03d42b773d93e0684 (diff)
downloadhaskell-65e13f66c595ad75bd6e9a55496f1372ead2731d.tar.gz
rts: Split up Itimer.c
This shouldn't have any functional changes. It merely splits up what are essentially three distinct codepaths which are melding together with CPP. At the moment I merely #include the implementation to use with CPP although this really feels very yucky. Reviewers: erikd, austin, simonmar Reviewed By: simonmar Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D2130
-rw-r--r--rts/posix/Itimer.c305
-rw-r--r--rts/posix/Signals.c29
-rw-r--r--rts/posix/Signals.h4
-rw-r--r--rts/posix/itimer/Pthread.c187
-rw-r--r--rts/posix/itimer/Setitimer.c88
-rw-r--r--rts/posix/itimer/TimerCreate.c93
6 files changed, 407 insertions, 299 deletions
diff --git a/rts/posix/Itimer.c b/rts/posix/Itimer.c
index 770ff202ea..ee93dd7719 100644
--- a/rts/posix/Itimer.c
+++ b/rts/posix/Itimer.c
@@ -13,37 +13,13 @@
* Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
* keen on getting access to @CLOCK_VIRTUAL@.
*
- * Hence, we use the old-fashioned @setitimer@ that just about everyone seems
- * to support. So much for standards.
+ * Hence, we often use the old-fashioned @setitimer@ that just about everyone
+ * seems to support. So much for standards.
*/
#include "PosixSource.h"
#include "Rts.h"
-#include "Ticker.h"
-#include "Itimer.h"
-#include "Proftimer.h"
-#include "Schedule.h"
-#include "Clock.h"
-
-/* As recommended in the autoconf manual */
-# ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-# else
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-# endif
-
-#ifdef HAVE_SIGNAL_H
-# include <signal.h>
-#endif
-
-#include <string.h>
-
/*
* timer_create doesn't exist and setitimer doesn't fire on iOS, so we're using
* a pthreads-based implementation. It may be to do with interference with the
@@ -60,58 +36,10 @@
* modified in user code using signals.
*/
#if defined(linux_HOST_OS) && defined(THREADED_RTS) && HAVE_SYS_TIMERFD_H
-#include <sys/timerfd.h>
-#include <fcntl.h>
#define USE_PTHREAD_FOR_ITIMER
-#define USE_TIMERFD_FOR_ITIMER 1
-#undef USE_TIMER_CREATE
-#else
-#define USE_TIMERFD_FOR_ITIMER 0
-#endif
-
-/*
- * TFD_CLOEXEC has been added in Linux 2.6.26.
- * If it is not available, we use fcntl(F_SETFD).
- */
-#ifndef TFD_CLOEXEC
-#define TFD_CLOEXEC 0
#endif
-#if defined(USE_PTHREAD_FOR_ITIMER)
-#include <pthread.h>
-#include <unistd.h>
-#endif
-
-/*
- * We use a realtime timer by default. I found this much more
- * reliable than a CPU timer:
- *
- * Experiments with different frequences: using
- * CLOCK_REALTIME/CLOCK_MONOTONIC on Linux 2.6.32,
- * 1000us has <1% impact on runtime
- * 100us has ~2% impact on runtime
- * 10us has ~40% impact on runtime
- *
- * using CLOCK_PROCESS_CPUTIME_ID on Linux 2.6.32,
- * I cannot get it to tick faster than 10ms (10000us)
- * which isn't great for profiling.
- *
- * In the threaded RTS, we can't tick in CPU time because the thread
- * which has the virtual timer might be idle, so the tick would never
- * fire. Therfore we used to tick in realtime in the threaded RTS and
- * in CPU time otherwise, but now we always tick in realtime, for
- * several reasons:
- *
- * - resolution (see above)
- * - consistency (-threaded is the same as normal)
- * - more consistency: Windows only has a realtime timer
- *
- * Note we want to use CLOCK_MONOTONIC rather than CLOCK_REALTIME,
- * because the latter may jump around (NTP adjustments, leap seconds
- * etc.).
- */
-
#if defined(solaris2_HOST_OS)
/* USE_TIMER_CREATE is usually disabled for Solaris. In fact it is
supported well on this OS, but requires additional privilege. When
@@ -130,232 +58,11 @@ ghc-stage2: timer_create: Not owner
#undef USE_TIMER_CREATE
#endif /* solaris2_HOST_OS */
-#if defined(USE_TIMER_CREATE)
-# define ITIMER_SIGNAL SIGVTALRM
-#elif defined(HAVE_SETITIMER)
-# define ITIMER_SIGNAL SIGALRM
- // Using SIGALRM can leads to problems, see #850. But we have no
- // option if timer_create() is not available.
-#else
-# error No way to set an interval timer.
-#endif
-
-#if defined(USE_TIMER_CREATE)
-static timer_t timer;
-#endif
-
-static Time itimer_interval = DEFAULT_TICK_INTERVAL;
-
-#if !defined(USE_PTHREAD_FOR_ITIMER)
-static void install_vtalrm_handler(TickProc handle_tick)
-{
- struct sigaction action;
-
- action.sa_handler = handle_tick;
-
- sigemptyset(&action.sa_mask);
-
-#ifdef SA_RESTART
- // specify SA_RESTART. One consequence if we don't do this is
- // that readline gets confused by the -threaded RTS. It seems
- // that if a SIGALRM handler is installed without SA_RESTART,
- // readline installs its own SIGALRM signal handler (see
- // readline's signals.c), and this somehow causes readline to go
- // wrong when the input exceeds a single line (try it).
- action.sa_flags = SA_RESTART;
-#else
- action.sa_flags = 0;
-#endif
-
- if (sigaction(ITIMER_SIGNAL, &action, NULL) == -1) {
- sysErrorBelch("sigaction");
- stg_exit(EXIT_FAILURE);
- }
-}
-#endif
-
+// Select the variant to use
#if defined(USE_PTHREAD_FOR_ITIMER)
-enum ItimerState {STOPPED, RUNNING, STOPPING, EXITED};
-static volatile enum ItimerState itimer_state = STOPPED;
-
-static void *itimer_thread_func(void *_handle_tick)
-{
- TickProc handle_tick = _handle_tick;
- uint64_t nticks;
- int timerfd = -1;
-
-#if USE_TIMERFD_FOR_ITIMER
- struct itimerspec it;
- it.it_value.tv_sec = TimeToSeconds(itimer_interval);
- it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
- it.it_interval = it.it_value;
-
- timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
- if (timerfd == -1) {
- sysErrorBelch("timerfd_create");
- stg_exit(EXIT_FAILURE);
- }
- if (!TFD_CLOEXEC) {
- fcntl(timerfd, F_SETFD, FD_CLOEXEC);
- }
- int ret = timerfd_settime(timerfd, 0, &it, NULL);
-#endif
-
- while (1) {
- if (USE_TIMERFD_FOR_ITIMER) {
- if (read(timerfd, &nticks, sizeof(nticks)) != sizeof(nticks)) {
- if (errno != EINTR) {
- sysErrorBelch("Itimer: read(timerfd) failed");
- }
- }
- } else {
- if (usleep(TimeToUS(itimer_interval)) != 0 && errno != EINTR) {
- sysErrorBelch("usleep(TimeToUS(itimer_interval) failed");
- }
- }
- switch (itimer_state) {
- case RUNNING:
- handle_tick(0);
- break;
- case STOPPED:
- break;
- case STOPPING:
- itimer_state = STOPPED;
- break;
- case EXITED:
- if (USE_TIMERFD_FOR_ITIMER)
- close(timerfd);
- return NULL;
- }
- }
- return NULL; // Never reached.
-}
-#endif
-
-void
-initTicker (Time interval, TickProc handle_tick)
-{
- itimer_interval = interval;
-
-#if defined(USE_PTHREAD_FOR_ITIMER)
- pthread_t tid;
- int r = pthread_create(&tid, NULL, itimer_thread_func, (void*)handle_tick);
- if (!r) {
- pthread_detach(tid);
-#if HAVE_PTHREAD_SETNAME_NP
- pthread_setname_np(tid, "ghc_ticker");
-#endif
- }
-#elif defined(USE_TIMER_CREATE)
- {
- struct sigevent ev;
-
- // Keep programs like valgrind happy
- memset(&ev, 0, sizeof(ev));
-
- ev.sigev_notify = SIGEV_SIGNAL;
- ev.sigev_signo = ITIMER_SIGNAL;
-
- if (timer_create(CLOCK_ID, &ev, &timer) != 0) {
- sysErrorBelch("timer_create");
- stg_exit(EXIT_FAILURE);
- }
- }
- install_vtalrm_handler(handle_tick);
-#else
- install_vtalrm_handler(handle_tick);
-#endif
-}
-
-void
-startTicker(void)
-{
-#if defined(USE_PTHREAD_FOR_ITIMER)
- // sanity check
- if (itimer_state == EXITED) {
- sysErrorBelch("ITimer: Tried to start a dead timer!\n");
- stg_exit(EXIT_FAILURE);
- }
- itimer_state = RUNNING;
+#include "itimer/Pthread.c"
#elif defined(USE_TIMER_CREATE)
- {
- struct itimerspec it;
-
- it.it_value.tv_sec = TimeToSeconds(itimer_interval);
- it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
- it.it_interval = it.it_value;
-
- if (timer_settime(timer, 0, &it, NULL) != 0) {
- sysErrorBelch("timer_settime");
- stg_exit(EXIT_FAILURE);
- }
- }
-#else
- {
- struct itimerval it;
-
- it.it_value.tv_sec = TimeToSeconds(itimer_interval);
- it.it_value.tv_usec = TimeToUS(itimer_interval) % 1000000;
- it.it_interval = it.it_value;
-
- if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
- sysErrorBelch("setitimer");
- stg_exit(EXIT_FAILURE);
- }
- }
-#endif
-}
-
-void
-stopTicker(void)
-{
-#if defined(USE_PTHREAD_FOR_ITIMER)
- if (itimer_state == RUNNING) {
- itimer_state = STOPPING;
- // Note that the timer may fire once more, but that's okay;
- // handle_tick is only called when itimer_state == RUNNING
- }
-#elif defined(USE_TIMER_CREATE)
- struct itimerspec it;
-
- it.it_value.tv_sec = 0;
- it.it_value.tv_nsec = 0;
- it.it_interval = it.it_value;
-
- if (timer_settime(timer, 0, &it, NULL) != 0) {
- sysErrorBelch("timer_settime");
- stg_exit(EXIT_FAILURE);
- }
+#include "itimer/TimerCreate.c"
#else
- struct itimerval it;
-
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = 0;
- it.it_interval = it.it_value;
-
- if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
- sysErrorBelch("setitimer");
- stg_exit(EXIT_FAILURE);
- }
+#include "itimer/Setitimer.c"
#endif
-}
-
-void
-exitTicker (rtsBool wait STG_UNUSED)
-{
-#if defined(USE_PTHREAD_FOR_ITIMER)
- itimer_state = EXITED;
-#elif defined(USE_TIMER_CREATE)
- // Before deleting the timer set the signal to ignore to avoid the
- // possibility of the signal being delivered after the timer is deleted.
- signal(ITIMER_SIGNAL, SIG_IGN);
- timer_delete(timer);
- // ignore errors - we don't really care if it fails.
-#endif
-}
-
-int
-rtsTimerSignal(void)
-{
- return ITIMER_SIGNAL;
-}
diff --git a/rts/posix/Signals.c b/rts/posix/Signals.c
index bfc7e82e15..7fb854b894 100644
--- a/rts/posix/Signals.c
+++ b/rts/posix/Signals.c
@@ -14,6 +14,7 @@
#include "Signals.h"
#include "RtsUtils.h"
#include "Prelude.h"
+#include "Ticker.h"
#include "Stable.h"
#include "Libdw.h"
@@ -626,6 +627,34 @@ set_sigtstp_action (rtsBool handle)
}
}
+/* Used by ItimerTimerCreate and ItimerSetitimer implementations */
+void
+install_vtalrm_handler(int sig, TickProc handle_tick)
+{
+ struct sigaction action;
+
+ action.sa_handler = handle_tick;
+
+ sigemptyset(&action.sa_mask);
+
+#ifdef SA_RESTART
+ // specify SA_RESTART. One consequence if we don't do this is
+ // that readline gets confused by the -threaded RTS. It seems
+ // that if a SIGALRM handler is installed without SA_RESTART,
+ // readline installs its own SIGALRM signal handler (see
+ // readline's signals.c), and this somehow causes readline to go
+ // wrong when the input exceeds a single line (try it).
+ action.sa_flags = SA_RESTART;
+#else
+ action.sa_flags = 0;
+#endif
+
+ if (sigaction(sig, &action, NULL) == -1) {
+ sysErrorBelch("sigaction");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
/* -----------------------------------------------------------------------------
* Install default signal handlers.
*
diff --git a/rts/posix/Signals.h b/rts/posix/Signals.h
index 3100d39537..bb9a7b58df 100644
--- a/rts/posix/Signals.h
+++ b/rts/posix/Signals.h
@@ -13,6 +13,8 @@
# include <signal.h>
#endif
+#include "Ticker.h"
+
#include "BeginPrivate.h"
rtsBool anyUserHandlers(void);
@@ -24,6 +26,8 @@ extern siginfo_t *next_pending_handler;
void startSignalHandlers(Capability *cap);
#endif
+void install_vtalrm_handler(int sig, TickProc handle_tick);
+
void ioManagerStartCap (/* inout */ Capability **cap);
extern StgInt *signal_handlers;
diff --git a/rts/posix/itimer/Pthread.c b/rts/posix/itimer/Pthread.c
new file mode 100644
index 0000000000..e84a53a058
--- /dev/null
+++ b/rts/posix/itimer/Pthread.c
@@ -0,0 +1,187 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1995-2007
+ *
+ * Interval timer for profiling and pre-emptive scheduling.
+ *
+ * ---------------------------------------------------------------------------*/
+
+/*
+ * We use a realtime timer by default. I found this much more
+ * reliable than a CPU timer:
+ *
+ * Experiments with different frequences: using
+ * CLOCK_REALTIME/CLOCK_MONOTONIC on Linux 2.6.32,
+ * 1000us has <1% impact on runtime
+ * 100us has ~2% impact on runtime
+ * 10us has ~40% impact on runtime
+ *
+ * using CLOCK_PROCESS_CPUTIME_ID on Linux 2.6.32,
+ * I cannot get it to tick faster than 10ms (10000us)
+ * which isn't great for profiling.
+ *
+ * In the threaded RTS, we can't tick in CPU time because the thread
+ * which has the virtual timer might be idle, so the tick would never
+ * fire. Therfore we used to tick in realtime in the threaded RTS and
+ * in CPU time otherwise, but now we always tick in realtime, for
+ * several reasons:
+ *
+ * - resolution (see above)
+ * - consistency (-threaded is the same as normal)
+ * - more consistency: Windows only has a realtime timer
+ *
+ * Note we want to use CLOCK_MONOTONIC rather than CLOCK_REALTIME,
+ * because the latter may jump around (NTP adjustments, leap seconds
+ * etc.).
+ */
+
+#include "PosixSource.h"
+#include "Rts.h"
+
+#include "Ticker.h"
+#include "posix/Itimer.h"
+#include "Proftimer.h"
+#include "Schedule.h"
+#include "posix/Clock.h"
+
+/* As recommended in the autoconf manual */
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#include <string.h>
+
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#if HAVE_SYS_TIMERFD_H
+#include <sys/timerfd.h>
+#define USE_TIMERFD_FOR_ITIMER 1
+#else
+#define USE_TIMERFD_FOR_ITIMER 0
+#endif
+
+/*
+ * TFD_CLOEXEC has been added in Linux 2.6.26.
+ * If it is not available, we use fcntl(F_SETFD).
+ */
+#ifndef TFD_CLOEXEC
+#define TFD_CLOEXEC 0
+#endif
+
+static Time itimer_interval = DEFAULT_TICK_INTERVAL;
+enum ItimerState {STOPPED, RUNNING, STOPPING, EXITED};
+static volatile enum ItimerState itimer_state = STOPPED;
+
+static void *itimer_thread_func(void *_handle_tick)
+{
+ TickProc handle_tick = _handle_tick;
+ uint64_t nticks;
+ int timerfd = -1;
+
+#if USE_TIMERFD_FOR_ITIMER
+ struct itimerspec it;
+ it.it_value.tv_sec = TimeToSeconds(itimer_interval);
+ it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
+ it.it_interval = it.it_value;
+
+ timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+ if (timerfd == -1) {
+ sysErrorBelch("timerfd_create");
+ stg_exit(EXIT_FAILURE);
+ }
+ if (!TFD_CLOEXEC) {
+ fcntl(timerfd, F_SETFD, FD_CLOEXEC);
+ }
+ int ret = timerfd_settime(timerfd, 0, &it, NULL);
+#endif
+
+ while (1) {
+ if (USE_TIMERFD_FOR_ITIMER) {
+ if (read(timerfd, &nticks, sizeof(nticks)) != sizeof(nticks)) {
+ if (errno != EINTR) {
+ sysErrorBelch("Itimer: read(timerfd) failed");
+ }
+ }
+ } else {
+ if (usleep(TimeToUS(itimer_interval)) != 0 && errno != EINTR) {
+ sysErrorBelch("usleep(TimeToUS(itimer_interval) failed");
+ }
+ }
+ switch (itimer_state) {
+ case RUNNING:
+ handle_tick(0);
+ break;
+ case STOPPED:
+ break;
+ case STOPPING:
+ itimer_state = STOPPED;
+ break;
+ case EXITED:
+ if (USE_TIMERFD_FOR_ITIMER)
+ close(timerfd);
+ return NULL;
+ }
+ }
+ return NULL; // Never reached.
+}
+
+void
+initTicker (Time interval, TickProc handle_tick)
+{
+ itimer_interval = interval;
+
+ pthread_t tid;
+ int r = pthread_create(&tid, NULL, itimer_thread_func, (void*)handle_tick);
+ if (!r) {
+ pthread_detach(tid);
+#if HAVE_PTHREAD_SETNAME_NP
+ pthread_setname_np(tid, "ghc_ticker");
+#endif
+ }
+}
+
+void
+startTicker(void)
+{
+ // sanity check
+ if (itimer_state == EXITED) {
+ sysErrorBelch("ITimer: Tried to start a dead timer!\n");
+ stg_exit(EXIT_FAILURE);
+ }
+ itimer_state = RUNNING;
+}
+
+void
+stopTicker(void)
+{
+ if (itimer_state == RUNNING) {
+ itimer_state = STOPPING;
+ // Note that the timer may fire once more, but that's okay;
+ // handle_tick is only called when itimer_state == RUNNING
+ }
+}
+
+void
+exitTicker (rtsBool wait STG_UNUSED)
+{
+ itimer_state = EXITED;
+}
+
+int
+rtsTimerSignal(void)
+{
+ return SIGALRM;
+}
diff --git a/rts/posix/itimer/Setitimer.c b/rts/posix/itimer/Setitimer.c
new file mode 100644
index 0000000000..c44e8d8c22
--- /dev/null
+++ b/rts/posix/itimer/Setitimer.c
@@ -0,0 +1,88 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1995-2007
+ *
+ * Interval timer for profiling and pre-emptive scheduling.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "PosixSource.h"
+#include "Rts.h"
+
+#include "Ticker.h"
+#include "posix/Itimer.h"
+#include "Proftimer.h"
+#include "Schedule.h"
+#include "posix/Clock.h"
+#include "posix/Signals.h"
+
+/* As recommended in the autoconf manual */
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#include <string.h>
+
+static Time itimer_interval = DEFAULT_TICK_INTERVAL;
+
+void
+initTicker (Time interval, TickProc handle_tick)
+{
+ itimer_interval = interval;
+ install_vtalrm_handler(SIGALRM, handle_tick);
+}
+
+void
+startTicker(void)
+{
+ struct itimerval it;
+
+ it.it_value.tv_sec = TimeToSeconds(itimer_interval);
+ it.it_value.tv_usec = TimeToUS(itimer_interval) % 1000000;
+ it.it_interval = it.it_value;
+
+ if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
+ sysErrorBelch("setitimer");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
+void
+stopTicker(void)
+{
+ struct itimerval it;
+
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_usec = 0;
+ it.it_interval = it.it_value;
+
+ if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
+ sysErrorBelch("setitimer");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
+void
+exitTicker (rtsBool wait STG_UNUSED)
+{
+ return;
+}
+
+int
+rtsTimerSignal(void)
+{
+ return SIGALRM;
+ // Using SIGALRM can leads to problems, see #850. But we have no
+ // option if timer_create() is not available.
+}
diff --git a/rts/posix/itimer/TimerCreate.c b/rts/posix/itimer/TimerCreate.c
new file mode 100644
index 0000000000..a4fb2b5b58
--- /dev/null
+++ b/rts/posix/itimer/TimerCreate.c
@@ -0,0 +1,93 @@
+/* -----------------------------------------------------------------------------
+ *
+ * (c) The GHC Team, 1995-2007
+ *
+ * Interval timer for profiling and pre-emptive scheduling.
+ *
+ * ---------------------------------------------------------------------------*/
+
+#include "PosixSource.h"
+#include "Rts.h"
+
+#include "Ticker.h"
+#include "posix/Itimer.h"
+#include "Proftimer.h"
+#include "Schedule.h"
+#include "posix/Clock.h"
+#include "posix/Signals.h"
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+#include <string.h>
+
+static Time itimer_interval = DEFAULT_TICK_INTERVAL;
+static timer_t timer;
+
+void
+initTicker (Time interval, TickProc handle_tick)
+{
+ itimer_interval = interval;
+
+ struct sigevent ev;
+
+ // Keep programs like valgrind happy
+ memset(&ev, 0, sizeof(ev));
+
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGVTALRM;
+
+ if (timer_create(CLOCK_ID, &ev, &timer) != 0) {
+ sysErrorBelch("timer_create");
+ stg_exit(EXIT_FAILURE);
+ }
+
+ install_vtalrm_handler(SIGVTALRM, handle_tick);
+}
+
+void
+startTicker(void)
+{
+ struct itimerspec it;
+
+ it.it_value.tv_sec = TimeToSeconds(itimer_interval);
+ it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
+ it.it_interval = it.it_value;
+
+ if (timer_settime(timer, 0, &it, NULL) != 0) {
+ sysErrorBelch("timer_settime");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
+void
+stopTicker(void)
+{
+ struct itimerspec it;
+
+ it.it_value.tv_sec = 0;
+ it.it_value.tv_nsec = 0;
+ it.it_interval = it.it_value;
+
+ if (timer_settime(timer, 0, &it, NULL) != 0) {
+ sysErrorBelch("timer_settime");
+ stg_exit(EXIT_FAILURE);
+ }
+}
+
+void
+exitTicker (rtsBool wait STG_UNUSED)
+{
+ // Before deleting the timer set the signal to ignore to avoid the
+ // possibility of the signal being delivered after the timer is deleted.
+ signal(SIGVTALRM, SIG_IGN);
+ timer_delete(timer);
+ // ignore errors - we don't really care if it fails.
+}
+
+int
+rtsTimerSignal(void)
+{
+ return SIGVTALRM;
+}