Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
8f95534a
by Duncan Coutts at 2026-04-01T19:01:52-04:00
-
51b32b0d
by Duncan Coutts at 2026-04-01T19:01:52-04:00
-
7562bcd7
by Duncan Coutts at 2026-04-01T19:01:52-04:00
-
6da127c7
by Duncan Coutts at 2026-04-01T19:01:52-04:00
-
3fd490fa
by Duncan Coutts at 2026-04-01T19:01:53-04:00
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:
| 1 | -# Check for a working timer_create(). We need a pretty detailed check
|
|
| 2 | -# here, because there exist partially-working implementations of
|
|
| 3 | -# timer_create() in certain versions of Linux (see bug #1933).
|
|
| 4 | -#
|
|
| 5 | -AC_DEFUN([FP_CHECK_TIMER_CREATE],[
|
|
| 6 | -AC_CHECK_FUNC([timer_create],[HAVE_timer_create=yes],[HAVE_timer_create=no])
|
|
| 7 | - |
|
| 8 | -if test "$HAVE_timer_create" = "yes"
|
|
| 9 | -then
|
|
| 10 | - if test "$cross_compiling" = "yes"
|
|
| 11 | - then
|
|
| 12 | - # We can't test timer_create when we're cross-compiling, so we
|
|
| 13 | - # optimistiaclly assume that it actually works properly.
|
|
| 14 | - AC_DEFINE([USE_TIMER_CREATE], 1, [Define to 1 if we can use timer_create(CLOCK_REALTIME,...)])
|
|
| 15 | - else
|
|
| 16 | - AC_CACHE_CHECK([for a working timer_create(CLOCK_REALTIME)],
|
|
| 17 | - [fptools_cv_timer_create_works],
|
|
| 18 | - [AC_TRY_RUN([
|
|
| 19 | -#include <stdio.h>
|
|
| 20 | -#if defined(HAVE_STDLIB_H)
|
|
| 21 | -#include <stdlib.h>
|
|
| 22 | -#endif
|
|
| 23 | -#include <time.h>
|
|
| 24 | -#if defined(HAVE_SIGNAL_H)
|
|
| 25 | -#include <signal.h>
|
|
| 26 | -#endif
|
|
| 27 | -#if defined(HAVE_UNISTD_H)
|
|
| 28 | -#include <unistd.h>
|
|
| 29 | -#endif
|
|
| 30 | - |
|
| 31 | -static volatile int tock = 0;
|
|
| 32 | -static void handler(int i)
|
|
| 33 | -{
|
|
| 34 | - tock = 1;
|
|
| 35 | -}
|
|
| 36 | - |
|
| 37 | -static void timeout(int i)
|
|
| 38 | -{
|
|
| 39 | - // timer_settime() has been known to hang, so just in case
|
|
| 40 | - // we install a 1-second timeout (see #2257)
|
|
| 41 | - exit(99);
|
|
| 42 | -}
|
|
| 43 | - |
|
| 44 | -int main(int argc, char *argv[])
|
|
| 45 | -{
|
|
| 46 | - |
|
| 47 | - struct sigevent ev;
|
|
| 48 | - timer_t timer;
|
|
| 49 | - struct itimerspec it;
|
|
| 50 | - struct sigaction action;
|
|
| 51 | - int m,n,count = 0;
|
|
| 52 | - |
|
| 53 | - ev.sigev_notify = SIGEV_SIGNAL;
|
|
| 54 | - ev.sigev_signo = SIGVTALRM;
|
|
| 55 | - |
|
| 56 | - action.sa_handler = handler;
|
|
| 57 | - action.sa_flags = 0;
|
|
| 58 | - sigemptyset(&action.sa_mask);
|
|
| 59 | - if (sigaction(SIGVTALRM, &action, NULL) == -1) {
|
|
| 60 | - fprintf(stderr,"SIGVTALRM problem\n");
|
|
| 61 | - exit(3);
|
|
| 62 | - }
|
|
| 63 | - |
|
| 64 | - action.sa_handler = timeout;
|
|
| 65 | - action.sa_flags = 0;
|
|
| 66 | - sigemptyset(&action.sa_mask);
|
|
| 67 | - if (sigaction(SIGALRM, &action, NULL) == -1) {
|
|
| 68 | - fprintf(stderr,"SIGALRM problem\n");
|
|
| 69 | - exit(3);
|
|
| 70 | - }
|
|
| 71 | - alarm(1);
|
|
| 72 | - |
|
| 73 | - if (timer_create(CLOCK_REALTIME, &ev, &timer) != 0) {
|
|
| 74 | - fprintf(stderr,"No CLOCK_REALTIME timer\n");
|
|
| 75 | - exit(2);
|
|
| 76 | - }
|
|
| 77 | - |
|
| 78 | - tock = 0;
|
|
| 79 | - |
|
| 80 | - it.it_value.tv_sec = 0;
|
|
| 81 | - it.it_value.tv_nsec = 1000000; // 1ms
|
|
| 82 | - it.it_interval = it.it_value;
|
|
| 83 | - if (timer_settime(timer, 0, &it, NULL) != 0) {
|
|
| 84 | - fprintf(stderr,"settime problem\n");
|
|
| 85 | - exit(4);
|
|
| 86 | - }
|
|
| 87 | - |
|
| 88 | - // some environments have coarse scheduler/timer granularity of ~10ms and worse
|
|
| 89 | - usleep(100000); // 100ms
|
|
| 90 | - |
|
| 91 | - if (!tock) {
|
|
| 92 | - fprintf(stderr,"no CLOCK_REALTIME signal\n");
|
|
| 93 | - exit(5);
|
|
| 94 | - }
|
|
| 95 | - |
|
| 96 | - timer_delete(timer);
|
|
| 97 | - |
|
| 98 | - exit(0);
|
|
| 99 | -}
|
|
| 100 | - ],
|
|
| 101 | - [fptools_cv_timer_create_works=yes],
|
|
| 102 | - [fptools_cv_timer_create_works=no])
|
|
| 103 | - ])
|
|
| 104 | -case $fptools_cv_timer_create_works in
|
|
| 105 | - yes) AC_DEFINE([USE_TIMER_CREATE], 1,
|
|
| 106 | - [Define to 1 if we can use timer_create(CLOCK_REALTIME,...)]);;
|
|
| 107 | -esac
|
|
| 108 | - fi
|
|
| 109 | -fi
|
|
| 110 | -]) |
| ... | ... | @@ -7,12 +7,14 @@ |
| 7 | 7 | * ---------------------------------------------------------------------------*/
|
| 8 | 8 | |
| 9 | 9 | /*
|
| 10 | - * The interval timer is used for profiling and for context switching in the
|
|
| 11 | - * threaded build.
|
|
| 10 | + * The interval timer is used for profiling and for context switching.
|
|
| 12 | 11 | *
|
| 13 | 12 | * This file defines the platform-independent view of interval timing, relying
|
| 14 | - * on platform-specific services to install and run the timers.
|
|
| 13 | + * on platform-specific services to install and run the timers. See
|
|
| 14 | + * posix/Ticker.c and win32/Ticker.c for the platform specific parts.
|
|
| 15 | 15 | *
|
| 16 | + * If you are looking for Itimer.c then you either file or one of the
|
|
| 17 | + * platform-specific Ticker.c files.
|
|
| 16 | 18 | */
|
| 17 | 19 | |
| 18 | 20 | #include "rts/PosixSource.h"
|
| ... | ... | @@ -204,7 +204,6 @@ FP_MUSTTAIL |
| 204 | 204 | |
| 205 | 205 | dnl ** check for librt
|
| 206 | 206 | AC_CHECK_FUNCS(clock_gettime timer_settime)
|
| 207 | -FP_CHECK_TIMER_CREATE
|
|
| 208 | 207 | |
| 209 | 208 | dnl ** check for Apple's "interesting" long double compatibility scheme
|
| 210 | 209 | AC_MSG_CHECKING(for printf\$LDBLStub)
|
| ... | ... | @@ -15,4 +15,4 @@ |
| 15 | 15 | |
| 16 | 16 | void startTimer (void);
|
| 17 | 17 | void stopTimer (void);
|
| 18 | -int rtsTimerSignal (void); |
|
| 18 | +int rtsTimerSignal (void); // Deprecated: see issue #27073 |
| ... | ... | @@ -21,7 +21,7 @@ void arm_atomic_spin_unlock(void); |
| 21 | 21 | // Unconditionally atomic operations
|
| 22 | 22 | // These are atomic even in the non-threaded RTS. These are necessary in the
|
| 23 | 23 | // Proftimer implementation, which may be called from the pthreads-based
|
| 24 | -// ITimer implementation.
|
|
| 24 | +// Ticker implementation.
|
|
| 25 | 25 | #define RELAXED_LOAD_ALWAYS(ptr) __atomic_load_n(ptr, __ATOMIC_RELAXED)
|
| 26 | 26 | #define RELAXED_STORE_ALWAYS(ptr,val) __atomic_store_n(ptr, val, __ATOMIC_RELAXED)
|
| 27 | 27 | #define RELAXED_ADD_ALWAYS(ptr,val) __atomic_add_fetch(ptr, val, __ATOMIC_RELAXED)
|
| ... | ... | @@ -640,35 +640,6 @@ set_sigtstp_action (bool handle) |
| 640 | 640 | }
|
| 641 | 641 | }
|
| 642 | 642 | |
| 643 | -/* Used by ItimerTimerCreate and ItimerSetitimer implementations */
|
|
| 644 | -void
|
|
| 645 | -install_vtalrm_handler(int sig, TickProc handle_tick)
|
|
| 646 | -{
|
|
| 647 | - struct sigaction action;
|
|
| 648 | - memset(&action, 0, sizeof(struct sigaction));
|
|
| 649 | - |
|
| 650 | - action.sa_handler = handle_tick;
|
|
| 651 | - |
|
| 652 | - sigemptyset(&action.sa_mask);
|
|
| 653 | - |
|
| 654 | -#if defined(SA_RESTART)
|
|
| 655 | - // specify SA_RESTART. One consequence if we don't do this is
|
|
| 656 | - // that readline gets confused by the -threaded RTS. It seems
|
|
| 657 | - // that if a SIGALRM handler is installed without SA_RESTART,
|
|
| 658 | - // readline installs its own SIGALRM signal handler (see
|
|
| 659 | - // readline's signals.c), and this somehow causes readline to go
|
|
| 660 | - // wrong when the input exceeds a single line (try it).
|
|
| 661 | - action.sa_flags = SA_RESTART;
|
|
| 662 | -#else
|
|
| 663 | - action.sa_flags = 0;
|
|
| 664 | -#endif
|
|
| 665 | - |
|
| 666 | - if (sigaction(sig, &action, NULL) == -1) {
|
|
| 667 | - sysErrorBelch("sigaction");
|
|
| 668 | - stg_exit(EXIT_FAILURE);
|
|
| 669 | - }
|
|
| 670 | -}
|
|
| 671 | - |
|
| 672 | 643 | /* -----------------------------------------------------------------------------
|
| 673 | 644 | * Install default signal handlers.
|
| 674 | 645 | *
|
| ... | ... | @@ -25,8 +25,6 @@ extern siginfo_t *next_pending_handler; |
| 25 | 25 | void startSignalHandlers(Capability *cap);
|
| 26 | 26 | #endif
|
| 27 | 27 | |
| 28 | -void install_vtalrm_handler(int sig, TickProc handle_tick);
|
|
| 29 | - |
|
| 30 | 28 | /* Communicating with the IO manager thread (see GHC.Conc).
|
| 31 | 29 | *
|
| 32 | 30 | * TODO: these I/O manager things are not related to signals and ought to live
|
| ... | ... | @@ -2,116 +2,38 @@ |
| 2 | 2 | *
|
| 3 | 3 | * (c) The GHC Team, 1995-2007
|
| 4 | 4 | *
|
| 5 | - * Interval timer for profiling and pre-emptive scheduling.
|
|
| 5 | + * Posix implementation(s) of the interval timer for profiling and pre-emptive
|
|
| 6 | + * scheduling.
|
|
| 6 | 7 | *
|
| 7 | 8 | * ---------------------------------------------------------------------------*/
|
| 8 | 9 | |
| 9 | -/*
|
|
| 10 | - * The interval timer is used for profiling and for context switching in the
|
|
| 11 | - * threaded build. Though POSIX 1003.1b includes a standard interface for
|
|
| 12 | - * such things, no one really seems to be implementing them yet. Even
|
|
| 13 | - * Solaris 2.3 only seems to provide support for @CLOCK_REAL@, whereas we're
|
|
| 14 | - * keen on getting access to @CLOCK_VIRTUAL@.
|
|
| 15 | - *
|
|
| 16 | - * Hence, we often use the old-fashioned @setitimer@ that just about everyone
|
|
| 17 | - * seems to support. So much for standards.
|
|
| 18 | - *
|
|
| 19 | - * If you are looking for Itimer.c then this is the right file. I renamed it
|
|
| 20 | - * Ticker.c for consistency.
|
|
| 10 | +/* The interval timer is used for profiling and for context switching.
|
|
| 11 | + * This file defines the platform-specific services to install and run the
|
|
| 12 | + * timers, and we call this the ticker. See rts/Timer.c for the
|
|
| 13 | + * platform-dependent view of interval timing.
|
|
| 14 | + *
|
|
| 15 | + * Historically we had ticker implementations using signals. This was always a
|
|
| 16 | + * rather shakey thing to do but we had few alternatives.
|
|
| 17 | + * - One problem with using signals is that there are severe limits on what
|
|
| 18 | + * code can be called from signal handlers. In particular it's not possible
|
|
| 19 | + * to take locks in a signal handler contex. This was enough for contex
|
|
| 20 | + * switching, but it's no good for things like flushing the eventlog, or
|
|
| 21 | + * waking up rts tasks.
|
|
| 22 | + * - We also want to avoid using alarm signals, as these can interrupt system
|
|
| 23 | + * calls (#10840) or can be overwritten by user code.
|
|
| 21 | 24 | */
|
| 22 | 25 | |
| 23 | -#include "rts/PosixSource.h"
|
|
| 24 | - |
|
| 25 | -/* We've defined _POSIX_SOURCE via "rts/PosixSource.h", and yet still use
|
|
| 26 | - some non-POSIX features. With _POSIX_SOURCE defined, visibility of
|
|
| 27 | - non-POSIX extension prototypes requires _DARWIN_C_SOURCE on Mac OS X,
|
|
| 28 | - __BSD_VISIBLE on FreeBSD and DragonflyBSD, and _NetBSD_SOURCE on
|
|
| 29 | - NetBSD. Otherwise, for example, code using pthread_setname_np(3) and
|
|
| 30 | - variants will not compile. We must therefore define the additional
|
|
| 31 | - macros that expose non-POSIX APIs early, before any of the relevant
|
|
| 32 | - system headers are included via "Rts.h".
|
|
| 33 | - |
|
| 34 | - An alternative approach could be to write portable wrappers or stubs for all
|
|
| 35 | - the non-posix functions in a C-module that does not include "rts/PosixSource.h",
|
|
| 36 | - and then use only POSIX features and the portable wrapper functions in all
|
|
| 37 | - other C-modules. */
|
|
| 38 | -#include "ghcconfig.h"
|
|
| 39 | -#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)
|
|
| 40 | -#define __BSD_VISIBLE 1
|
|
| 41 | -#endif
|
|
| 42 | -#if defined(darwin_HOST_OS)
|
|
| 43 | -#define _DARWIN_C_SOURCE 1
|
|
| 44 | -#endif
|
|
| 45 | -#if defined(netbsd_HOST_OS)
|
|
| 46 | -#define _NETBSD_SOURCE 1
|
|
| 47 | -#endif
|
|
| 48 | - |
|
| 49 | -#include "Rts.h"
|
|
| 50 | - |
|
| 51 | -/*
|
|
| 52 | - * It used to be that timer_create doesn't exist on iOS and setitimer doesn't fire on iOS
|
|
| 53 | - * during debugging. See #7723. Seems to be an issue with signals.
|
|
| 54 | - *
|
|
| 55 | - * We also want to avoid using alarm signals, as these can interrupt system calls (#10840)
|
|
| 56 | - * or can be overwritten by user code.
|
|
| 26 | +/* Select a ticker implementation to use:
|
|
| 57 | 27 | *
|
| 58 | - * So we are using the pthread based implementation.
|
|
| 59 | - */
|
|
| 60 | -#if defined(ios_HOST_OS) || defined(darwin_HOST_OS)
|
|
| 61 | -#define USE_PTHREAD_FOR_ITIMER
|
|
| 62 | -#endif
|
|
| 63 | - |
|
| 64 | -/*
|
|
| 65 | - * On Linux we can use timerfd_* (introduced in Linux
|
|
| 66 | - * 2.6.25) and a thread instead of alarm signals. It avoids the risk of
|
|
| 67 | - * interrupting syscalls (see #10840) and the risk of being accidentally
|
|
| 68 | - * modified in user code using signals. NetBSD has also added timerfd
|
|
| 69 | - * support since version 10.
|
|
| 28 | + * On modern Linux, FreeBSD and NetBSD we can use timerfd_create and a thread
|
|
| 29 | + * that waits on it using poll. Linux has had timerfd since version 2.6.25.
|
|
| 30 | + * NetBSD has had timerfd since version 10, and FreeBSD since version 15.
|
|
| 70 | 31 | *
|
| 71 | - * For older version of linux/netbsd without timerfd we fall back to the
|
|
| 72 | - * pthread based implementation.
|
|
| 32 | + * For older version of linux/bsd without timerfd, and for all other posix
|
|
| 33 | + * platforms, we use the implementation using posix pthreads and nanosleep().
|
|
| 73 | 34 | */
|
| 74 | 35 | #if defined(HAVE_SYS_TIMERFD_H)
|
| 75 | -#define USE_TIMERFD_FOR_ITIMER
|
|
| 76 | -#endif
|
|
| 77 | - |
|
| 78 | -#if defined(linux_HOST_OS)
|
|
| 79 | -#define USE_PTHREAD_FOR_ITIMER
|
|
| 80 | -#endif
|
|
| 81 | - |
|
| 82 | -#if defined(netbsd_HOST_OS)
|
|
| 83 | -#define USE_PTHREAD_FOR_ITIMER
|
|
| 84 | -#endif
|
|
| 85 | - |
|
| 86 | -#if defined(freebsd_HOST_OS)
|
|
| 87 | -#define USE_PTHREAD_FOR_ITIMER
|
|
| 88 | -#endif
|
|
| 89 | - |
|
| 90 | -#if defined(solaris2_HOST_OS)
|
|
| 91 | -/* USE_TIMER_CREATE is usually disabled for Solaris. In fact it is
|
|
| 92 | - supported well on this OS, but requires additional privilege. When
|
|
| 93 | - user does not have it, then the testing configure program fails
|
|
| 94 | - which results in USE_TIMER_CREATE not defined.
|
|
| 95 | - On the other hand when we cross-compile, then we optimistically
|
|
| 96 | - assume usage of timer_create function. The problem is that if we
|
|
| 97 | - cross compile for example from i386-solaris2 to x86_64-solaris2,
|
|
| 98 | - then the build fails with error like this:
|
|
| 99 | - |
|
| 100 | -ghc-stage2: timer_create: Not owner
|
|
| 101 | - |
|
| 102 | - which happens on first ghc-stage2 invocation. So to support
|
|
| 103 | - cross-compilation to Solaris we manually undefine USE_TIMER_CREATE
|
|
| 104 | - here */
|
|
| 105 | -#undef USE_TIMER_CREATE
|
|
| 106 | -#endif /* solaris2_HOST_OS */
|
|
| 107 | - |
|
| 108 | -// Select the variant to use
|
|
| 109 | -#if defined(USE_TIMERFD_FOR_ITIMER)
|
|
| 110 | 36 | #include "ticker/TimerFd.c"
|
| 111 | -#elif defined(USE_PTHREAD_FOR_ITIMER)
|
|
| 112 | -#include "ticker/Pthread.c"
|
|
| 113 | -#elif defined(USE_TIMER_CREATE)
|
|
| 114 | -#include "ticker/TimerCreate.c"
|
|
| 115 | 37 | #else
|
| 116 | -#include "ticker/Setitimer.c"
|
|
| 38 | +#include "ticker/Pthread.c"
|
|
| 117 | 39 | #endif |
| 1 | -/* -----------------------------------------------------------------------------
|
|
| 2 | - *
|
|
| 3 | - * (c) The GHC Team, 1995-2007
|
|
| 4 | - *
|
|
| 5 | - * Interval timer for profiling and pre-emptive scheduling.
|
|
| 6 | - *
|
|
| 7 | - * ---------------------------------------------------------------------------*/
|
|
| 8 | - |
|
| 9 | -#include "rts/PosixSource.h"
|
|
| 10 | -#include "Rts.h"
|
|
| 11 | - |
|
| 12 | -#include "Ticker.h"
|
|
| 13 | -#include "Proftimer.h"
|
|
| 14 | -#include "Schedule.h"
|
|
| 15 | -#include "posix/Clock.h"
|
|
| 16 | -#include "posix/Signals.h"
|
|
| 17 | - |
|
| 18 | -#include <time.h>
|
|
| 19 | -#if HAVE_SYS_TIME_H
|
|
| 20 | -# include <sys/time.h>
|
|
| 21 | -#endif
|
|
| 22 | - |
|
| 23 | -#if defined(HAVE_SIGNAL_H)
|
|
| 24 | -# include <signal.h>
|
|
| 25 | -#endif
|
|
| 26 | - |
|
| 27 | -#include <string.h>
|
|
| 28 | - |
|
| 29 | -static Time itimer_interval = DEFAULT_TICK_INTERVAL;
|
|
| 30 | - |
|
| 31 | -void
|
|
| 32 | -initTicker (Time interval, TickProc handle_tick)
|
|
| 33 | -{
|
|
| 34 | - itimer_interval = interval;
|
|
| 35 | - install_vtalrm_handler(SIGALRM, handle_tick);
|
|
| 36 | -}
|
|
| 37 | - |
|
| 38 | -void
|
|
| 39 | -startTicker(void)
|
|
| 40 | -{
|
|
| 41 | - struct itimerval it;
|
|
| 42 | - |
|
| 43 | - it.it_value.tv_sec = TimeToSeconds(itimer_interval);
|
|
| 44 | - it.it_value.tv_usec = TimeToUS(itimer_interval) % 1000000;
|
|
| 45 | - it.it_interval = it.it_value;
|
|
| 46 | - |
|
| 47 | - if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
|
|
| 48 | - sysErrorBelch("setitimer");
|
|
| 49 | - stg_exit(EXIT_FAILURE);
|
|
| 50 | - }
|
|
| 51 | -}
|
|
| 52 | - |
|
| 53 | -void
|
|
| 54 | -stopTicker(void)
|
|
| 55 | -{
|
|
| 56 | - struct itimerval it;
|
|
| 57 | - |
|
| 58 | - it.it_value.tv_sec = 0;
|
|
| 59 | - it.it_value.tv_usec = 0;
|
|
| 60 | - it.it_interval = it.it_value;
|
|
| 61 | - |
|
| 62 | - if (setitimer(ITIMER_REAL, &it, NULL) != 0) {
|
|
| 63 | - sysErrorBelch("setitimer");
|
|
| 64 | - stg_exit(EXIT_FAILURE);
|
|
| 65 | - }
|
|
| 66 | -}
|
|
| 67 | - |
|
| 68 | -void
|
|
| 69 | -exitTicker (bool wait STG_UNUSED)
|
|
| 70 | -{
|
|
| 71 | - return;
|
|
| 72 | -}
|
|
| 73 | - |
|
| 74 | -int
|
|
| 75 | -rtsTimerSignal(void)
|
|
| 76 | -{
|
|
| 77 | - return SIGALRM;
|
|
| 78 | - // Using SIGALRM can leads to problems, see #850. But we have no
|
|
| 79 | - // option if timer_create() is not available.
|
|
| 80 | -} |
| 1 | -/* -----------------------------------------------------------------------------
|
|
| 2 | - *
|
|
| 3 | - * (c) The GHC Team, 1995-2007
|
|
| 4 | - *
|
|
| 5 | - * Interval timer for profiling and pre-emptive scheduling.
|
|
| 6 | - *
|
|
| 7 | - * ---------------------------------------------------------------------------*/
|
|
| 8 | - |
|
| 9 | -#include "rts/PosixSource.h"
|
|
| 10 | -#include "Rts.h"
|
|
| 11 | - |
|
| 12 | -#include "Ticker.h"
|
|
| 13 | -#include "Proftimer.h"
|
|
| 14 | -#include "Schedule.h"
|
|
| 15 | -#include "posix/Clock.h"
|
|
| 16 | -#include "posix/Signals.h"
|
|
| 17 | - |
|
| 18 | -#if defined(HAVE_SIGNAL_H)
|
|
| 19 | -# include <signal.h>
|
|
| 20 | -#endif
|
|
| 21 | - |
|
| 22 | -#include <string.h>
|
|
| 23 | - |
|
| 24 | -static Time itimer_interval = DEFAULT_TICK_INTERVAL;
|
|
| 25 | -static timer_t timer;
|
|
| 26 | - |
|
| 27 | -void
|
|
| 28 | -initTicker (Time interval, TickProc handle_tick)
|
|
| 29 | -{
|
|
| 30 | - itimer_interval = interval;
|
|
| 31 | - |
|
| 32 | - struct sigevent ev;
|
|
| 33 | - |
|
| 34 | - // Keep programs like valgrind happy
|
|
| 35 | - memset(&ev, 0, sizeof(ev));
|
|
| 36 | - |
|
| 37 | - ev.sigev_notify = SIGEV_SIGNAL;
|
|
| 38 | - ev.sigev_signo = SIGVTALRM;
|
|
| 39 | - |
|
| 40 | - if (timer_create(CLOCK_ID, &ev, &timer) != 0) {
|
|
| 41 | - sysErrorBelch("timer_create");
|
|
| 42 | - stg_exit(EXIT_FAILURE);
|
|
| 43 | - }
|
|
| 44 | - |
|
| 45 | - install_vtalrm_handler(SIGVTALRM, handle_tick);
|
|
| 46 | -}
|
|
| 47 | - |
|
| 48 | -void
|
|
| 49 | -startTicker(void)
|
|
| 50 | -{
|
|
| 51 | - struct itimerspec it;
|
|
| 52 | - |
|
| 53 | - it.it_value.tv_sec = TimeToSeconds(itimer_interval);
|
|
| 54 | - it.it_value.tv_nsec = TimeToNS(itimer_interval) % 1000000000;
|
|
| 55 | - it.it_interval = it.it_value;
|
|
| 56 | - |
|
| 57 | - if (timer_settime(timer, 0, &it, NULL) != 0) {
|
|
| 58 | - sysErrorBelch("timer_settime");
|
|
| 59 | - stg_exit(EXIT_FAILURE);
|
|
| 60 | - }
|
|
| 61 | -}
|
|
| 62 | - |
|
| 63 | -void
|
|
| 64 | -stopTicker(void)
|
|
| 65 | -{
|
|
| 66 | - struct itimerspec it;
|
|
| 67 | - |
|
| 68 | - it.it_value.tv_sec = 0;
|
|
| 69 | - it.it_value.tv_nsec = 0;
|
|
| 70 | - it.it_interval = it.it_value;
|
|
| 71 | - |
|
| 72 | - if (timer_settime(timer, 0, &it, NULL) != 0) {
|
|
| 73 | - sysErrorBelch("timer_settime");
|
|
| 74 | - stg_exit(EXIT_FAILURE);
|
|
| 75 | - }
|
|
| 76 | -}
|
|
| 77 | - |
|
| 78 | -void
|
|
| 79 | -exitTicker (bool wait STG_UNUSED)
|
|
| 80 | -{
|
|
| 81 | - // Before deleting the timer set the signal to ignore to avoid the
|
|
| 82 | - // possibility of the signal being delivered after the timer is deleted.
|
|
| 83 | - signal(SIGVTALRM, SIG_IGN);
|
|
| 84 | - timer_delete(timer);
|
|
| 85 | - // ignore errors - we don't really care if it fails.
|
|
| 86 | -}
|
|
| 87 | - |
|
| 88 | -int
|
|
| 89 | -rtsTimerSignal(void)
|
|
| 90 | -{
|
|
| 91 | - return SIGVTALRM;
|
|
| 92 | -} |