Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
8f95534a by Duncan Coutts at 2026-04-01T19:01:52-04:00
Remove signal-based ticker implementations
Fixes issue #27073
All supported platforms should work with the pthreads + nanosleep based
ticker implementation. This avoids all the problems with using signals.
In practice, all supported platforms were probably using the non-signal
tickers already, which is probably why we do not get lots of reports
about deadlocks and other weirdness: we were definately using functions
that are not async signal safe in the tick handler (such as fflush to
flussh the eventlog).
Only Solaris was explicitly using the timer_create ticker impl, and even
Solaris could probably use the pthreads one (if anyone cared: Solaris is
no longer a Teir 3 supported platform).
Plausibly the only supported platform that this will change will be AIX,
which should now use the pthreads impl.
- - - - -
51b32b0d by Duncan Coutts at 2026-04-01T19:01:52-04:00
Tidy up some timer/ticker comments elsewhere
- - - - -
7562bcd7 by Duncan Coutts at 2026-04-01T19:01:52-04:00
Remove now-unused install_vtalrm_handler
Support function used by both of the signal-based ticker
implementations.
- - - - -
6da127c7 by Duncan Coutts at 2026-04-01T19:01:52-04:00
No longer probe for timer_create in rts/configure
It was only used by the TimerCreate.c ticker impl.
- - - - -
3fd490fa by Duncan Coutts at 2026-04-01T19:01:53-04:00
Note that rtsTimerSignal is deprecated.
- - - - -
10 changed files:
- − m4/fp_check_timer_create.m4
- rts/Timer.c
- rts/configure.ac
- rts/include/rts/Timer.h
- rts/include/stg/SMP.h
- rts/posix/Signals.c
- rts/posix/Signals.h
- rts/posix/Ticker.c
- − rts/posix/ticker/Setitimer.c
- − rts/posix/ticker/TimerCreate.c
Changes:
=====================================
m4/fp_check_timer_create.m4 deleted
=====================================
@@ -1,110 +0,0 @@
-# Check for a working timer_create(). We need a pretty detailed check
-# here, because there exist partially-working implementations of
-# timer_create() in certain versions of Linux (see bug #1933).
-#
-AC_DEFUN([FP_CHECK_TIMER_CREATE],[
-AC_CHECK_FUNC([timer_create],[HAVE_timer_create=yes],[HAVE_timer_create=no])
-
-if test "$HAVE_timer_create" = "yes"
-then
- if test "$cross_compiling" = "yes"
- then
- # We can't test timer_create when we're cross-compiling, so we
- # optimistiaclly assume that it actually works properly.
- AC_DEFINE([USE_TIMER_CREATE], 1, [Define to 1 if we can use timer_create(CLOCK_REALTIME,...)])
- else
- AC_CACHE_CHECK([for a working timer_create(CLOCK_REALTIME)],
- [fptools_cv_timer_create_works],
- [AC_TRY_RUN([
-#include
-#if defined(HAVE_STDLIB_H)
-#include
-#endif
-#include
-#if defined(HAVE_SIGNAL_H)
-#include
-#endif
-#if defined(HAVE_UNISTD_H)
-#include
-#endif
-
-static volatile int tock = 0;
-static void handler(int i)
-{
- tock = 1;
-}
-
-static void timeout(int i)
-{
- // timer_settime() has been known to hang, so just in case
- // we install a 1-second timeout (see #2257)
- exit(99);
-}
-
-int main(int argc, char *argv[])
-{
-
- struct sigevent ev;
- timer_t timer;
- struct itimerspec it;
- struct sigaction action;
- int m,n,count = 0;
-
- ev.sigev_notify = SIGEV_SIGNAL;
- ev.sigev_signo = SIGVTALRM;
-
- action.sa_handler = handler;
- action.sa_flags = 0;
- sigemptyset(&action.sa_mask);
- if (sigaction(SIGVTALRM, &action, NULL) == -1) {
- fprintf(stderr,"SIGVTALRM problem\n");
- exit(3);
- }
-
- action.sa_handler = timeout;
- action.sa_flags = 0;
- sigemptyset(&action.sa_mask);
- if (sigaction(SIGALRM, &action, NULL) == -1) {
- fprintf(stderr,"SIGALRM problem\n");
- exit(3);
- }
- alarm(1);
-
- if (timer_create(CLOCK_REALTIME, &ev, &timer) != 0) {
- fprintf(stderr,"No CLOCK_REALTIME timer\n");
- exit(2);
- }
-
- tock = 0;
-
- it.it_value.tv_sec = 0;
- it.it_value.tv_nsec = 1000000; // 1ms
- it.it_interval = it.it_value;
- if (timer_settime(timer, 0, &it, NULL) != 0) {
- fprintf(stderr,"settime problem\n");
- exit(4);
- }
-
- // some environments have coarse scheduler/timer granularity of ~10ms and worse
- usleep(100000); // 100ms
-
- if (!tock) {
- fprintf(stderr,"no CLOCK_REALTIME signal\n");
- exit(5);
- }
-
- timer_delete(timer);
-
- exit(0);
-}
- ],
- [fptools_cv_timer_create_works=yes],
- [fptools_cv_timer_create_works=no])
- ])
-case $fptools_cv_timer_create_works in
- yes) AC_DEFINE([USE_TIMER_CREATE], 1,
- [Define to 1 if we can use timer_create(CLOCK_REALTIME,...)]);;
-esac
- fi
-fi
-])
=====================================
rts/Timer.c
=====================================
@@ -7,12 +7,14 @@
* ---------------------------------------------------------------------------*/
/*
- * The interval timer is used for profiling and for context switching in the
- * threaded build.
+ * The interval timer is used for profiling and for context switching.
*
* This file defines the platform-independent view of interval timing, relying
- * on platform-specific services to install and run the timers.
+ * on platform-specific services to install and run the timers. See
+ * posix/Ticker.c and win32/Ticker.c for the platform specific parts.
*
+ * If you are looking for Itimer.c then you either file or one of the
+ * platform-specific Ticker.c files.
*/
#include "rts/PosixSource.h"
=====================================
rts/configure.ac
=====================================
@@ -204,7 +204,6 @@ FP_MUSTTAIL
dnl ** check for librt
AC_CHECK_FUNCS(clock_gettime timer_settime)
-FP_CHECK_TIMER_CREATE
dnl ** check for Apple's "interesting" long double compatibility scheme
AC_MSG_CHECKING(for printf\$LDBLStub)
=====================================
rts/include/rts/Timer.h
=====================================
@@ -15,4 +15,4 @@
void startTimer (void);
void stopTimer (void);
-int rtsTimerSignal (void);
+int rtsTimerSignal (void); // Deprecated: see issue #27073
=====================================
rts/include/stg/SMP.h
=====================================
@@ -21,7 +21,7 @@ void arm_atomic_spin_unlock(void);
// Unconditionally atomic operations
// These are atomic even in the non-threaded RTS. These are necessary in the
// Proftimer implementation, which may be called from the pthreads-based
-// ITimer implementation.
+// Ticker implementation.
#define RELAXED_LOAD_ALWAYS(ptr) __atomic_load_n(ptr, __ATOMIC_RELAXED)
#define RELAXED_STORE_ALWAYS(ptr,val) __atomic_store_n(ptr, val, __ATOMIC_RELAXED)
#define RELAXED_ADD_ALWAYS(ptr,val) __atomic_add_fetch(ptr, val, __ATOMIC_RELAXED)
=====================================
rts/posix/Signals.c
=====================================
@@ -640,35 +640,6 @@ set_sigtstp_action (bool handle)
}
}
-/* Used by ItimerTimerCreate and ItimerSetitimer implementations */
-void
-install_vtalrm_handler(int sig, TickProc handle_tick)
-{
- struct sigaction action;
- memset(&action, 0, sizeof(struct sigaction));
-
- action.sa_handler = handle_tick;
-
- sigemptyset(&action.sa_mask);
-
-#if defined(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.
*
=====================================
rts/posix/Signals.h
=====================================
@@ -25,8 +25,6 @@ extern siginfo_t *next_pending_handler;
void startSignalHandlers(Capability *cap);
#endif
-void install_vtalrm_handler(int sig, TickProc handle_tick);
-
/* Communicating with the IO manager thread (see GHC.Conc).
*
* TODO: these I/O manager things are not related to signals and ought to live
=====================================
rts/posix/Ticker.c
=====================================
@@ -2,116 +2,38 @@
*
* (c) The GHC Team, 1995-2007
*
- * Interval timer for profiling and pre-emptive scheduling.
+ * Posix implementation(s) of the interval timer for profiling and pre-emptive
+ * scheduling.
*
* ---------------------------------------------------------------------------*/
-/*
- * The interval timer is used for profiling and for context switching in the
- * threaded build. Though POSIX 1003.1b includes a standard interface for
- * such things, no one really seems to be implementing them yet. Even
- * Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
- * keen on getting access to @CLOCK_VIRTUAL@.
- *
- * Hence, we often use the old-fashioned @setitimer@ that just about everyone
- * seems to support. So much for standards.
- *
- * If you are looking for Itimer.c then this is the right file. I renamed it
- * Ticker.c for consistency.
+/* The interval timer is used for profiling and for context switching.
+ * This file defines the platform-specific services to install and run the
+ * timers, and we call this the ticker. See rts/Timer.c for the
+ * platform-dependent view of interval timing.
+ *
+ * Historically we had ticker implementations using signals. This was always a
+ * rather shakey thing to do but we had few alternatives.
+ * - One problem with using signals is that there are severe limits on what
+ * code can be called from signal handlers. In particular it's not possible
+ * to take locks in a signal handler contex. This was enough for contex
+ * switching, but it's no good for things like flushing the eventlog, or
+ * waking up rts tasks.
+ * - We also want to avoid using alarm signals, as these can interrupt system
+ * calls (#10840) or can be overwritten by user code.
*/
-#include "rts/PosixSource.h"
-
-/* We've defined _POSIX_SOURCE via "rts/PosixSource.h", and yet still use
- some non-POSIX features. With _POSIX_SOURCE defined, visibility of
- non-POSIX extension prototypes requires _DARWIN_C_SOURCE on Mac OS X,
- __BSD_VISIBLE on FreeBSD and DragonflyBSD, and _NetBSD_SOURCE on
- NetBSD. Otherwise, for example, code using pthread_setname_np(3) and
- variants will not compile. We must therefore define the additional
- macros that expose non-POSIX APIs early, before any of the relevant
- system headers are included via "Rts.h".
-
- An alternative approach could be to write portable wrappers or stubs for all
- the non-posix functions in a C-module that does not include "rts/PosixSource.h",
- and then use only POSIX features and the portable wrapper functions in all
- other C-modules. */
-#include "ghcconfig.h"
-#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)
-#define __BSD_VISIBLE 1
-#endif
-#if defined(darwin_HOST_OS)
-#define _DARWIN_C_SOURCE 1
-#endif
-#if defined(netbsd_HOST_OS)
-#define _NETBSD_SOURCE 1
-#endif
-
-#include "Rts.h"
-
-/*
- * It used to be that timer_create doesn't exist on iOS and setitimer doesn't fire on iOS
- * during debugging. See #7723. Seems to be an issue with signals.
- *
- * We also want to avoid using alarm signals, as these can interrupt system calls (#10840)
- * or can be overwritten by user code.
+/* Select a ticker implementation to use:
*
- * So we are using the pthread based implementation.
- */
-#if defined(ios_HOST_OS) || defined(darwin_HOST_OS)
-#define USE_PTHREAD_FOR_ITIMER
-#endif
-
-/*
- * On Linux we can use timerfd_* (introduced in Linux
- * 2.6.25) and a thread instead of alarm signals. It avoids the risk of
- * interrupting syscalls (see #10840) and the risk of being accidentally
- * modified in user code using signals. NetBSD has also added timerfd
- * support since version 10.
+ * On modern Linux, FreeBSD and NetBSD we can use timerfd_create and a thread
+ * that waits on it using poll. Linux has had timerfd since version 2.6.25.
+ * NetBSD has had timerfd since version 10, and FreeBSD since version 15.
*
- * For older version of linux/netbsd without timerfd we fall back to the
- * pthread based implementation.
+ * For older version of linux/bsd without timerfd, and for all other posix
+ * platforms, we use the implementation using posix pthreads and nanosleep().
*/
#if defined(HAVE_SYS_TIMERFD_H)
-#define USE_TIMERFD_FOR_ITIMER
-#endif
-
-#if defined(linux_HOST_OS)
-#define USE_PTHREAD_FOR_ITIMER
-#endif
-
-#if defined(netbsd_HOST_OS)
-#define USE_PTHREAD_FOR_ITIMER
-#endif
-
-#if defined(freebsd_HOST_OS)
-#define USE_PTHREAD_FOR_ITIMER
-#endif
-
-#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
- user does not have it, then the testing configure program fails
- which results in USE_TIMER_CREATE not defined.
- On the other hand when we cross-compile, then we optimistically
- assume usage of timer_create function. The problem is that if we
- cross compile for example from i386-solaris2 to x86_64-solaris2,
- then the build fails with error like this:
-
-ghc-stage2: timer_create: Not owner
-
- which happens on first ghc-stage2 invocation. So to support
- cross-compilation to Solaris we manually undefine USE_TIMER_CREATE
- here */
-#undef USE_TIMER_CREATE
-#endif /* solaris2_HOST_OS */
-
-// Select the variant to use
-#if defined(USE_TIMERFD_FOR_ITIMER)
#include "ticker/TimerFd.c"
-#elif defined(USE_PTHREAD_FOR_ITIMER)
-#include "ticker/Pthread.c"
-#elif defined(USE_TIMER_CREATE)
-#include "ticker/TimerCreate.c"
#else
-#include "ticker/Setitimer.c"
+#include "ticker/Pthread.c"
#endif
=====================================
rts/posix/ticker/Setitimer.c deleted
=====================================
@@ -1,80 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * (c) The GHC Team, 1995-2007
- *
- * Interval timer for profiling and pre-emptive scheduling.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "rts/PosixSource.h"
-#include "Rts.h"
-
-#include "Ticker.h"
-#include "Proftimer.h"
-#include "Schedule.h"
-#include "posix/Clock.h"
-#include "posix/Signals.h"
-
-#include
-#if HAVE_SYS_TIME_H
-# include
-#endif
-
-#if defined(HAVE_SIGNAL_H)
-# include
-#endif
-
-#include
-
-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 (bool 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.
-}
=====================================
rts/posix/ticker/TimerCreate.c deleted
=====================================
@@ -1,92 +0,0 @@
-/* -----------------------------------------------------------------------------
- *
- * (c) The GHC Team, 1995-2007
- *
- * Interval timer for profiling and pre-emptive scheduling.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "rts/PosixSource.h"
-#include "Rts.h"
-
-#include "Ticker.h"
-#include "Proftimer.h"
-#include "Schedule.h"
-#include "posix/Clock.h"
-#include "posix/Signals.h"
-
-#if defined(HAVE_SIGNAL_H)
-# include
-#endif
-
-#include
-
-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 (bool 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;
-}
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/5ae43275ae8fa1a6938f2efcc774c36...
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/5ae43275ae8fa1a6938f2efcc774c36...
You're receiving this email because of your account on gitlab.haskell.org.