[Git][ghc/ghc][master] 5 commits: Remove signal-based ticker implementations
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 <stdio.h> -#if defined(HAVE_STDLIB_H) -#include <stdlib.h> -#endif -#include <time.h> -#if defined(HAVE_SIGNAL_H) -#include <signal.h> -#endif -#if defined(HAVE_UNISTD_H) -#include <unistd.h> -#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 <time.h> -#if HAVE_SYS_TIME_H -# include <sys/time.h> -#endif - -#if defined(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 (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 <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 (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.
participants (1)
-
Marge Bot (@marge-bot)