#include #include #include #include #include #include #include #include #include #if defined(__APPLE__) /* * clock_nanosleep is missing on all macOS version, add emulation. */ /* scale factors */ #define TIMING_GIGA 1000000000 #define TIMER_ABSTIME 0 /* not used */ /* timespec difference (monotonic) right - left */ static inline void timespec_monodiff_rml(struct timespec *ts_out, const struct timespec *ts_in) { /* * out = in - out, * where in > out */ ts_out->tv_sec = ts_in->tv_sec - ts_out->tv_sec; ts_out->tv_nsec = ts_in->tv_nsec - ts_out->tv_nsec; if (ts_out->tv_sec < 0) { ts_out->tv_sec = 0; ts_out->tv_nsec = 0; } else if (ts_out->tv_nsec < 0) { if (ts_out->tv_sec == 0) { ts_out->tv_sec = 0; ts_out->tv_nsec = 0; } else { ts_out->tv_sec = ts_out->tv_sec - 1; ts_out->tv_nsec = ts_out->tv_nsec + TIMING_GIGA; } } } static inline int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *req, struct timespec *remain) { struct timespec ts_delta; int retval = clock_gettime(clock_id, &ts_delta); (void)remain; (void)flags; if (retval == 0) { timespec_monodiff_rml(&ts_delta, req); retval = nanosleep(&ts_delta, NULL); } return retval; } #endif static volatile int run = 1; static int dummy[10]; static sem_t sem; static void add (void) { int i; for (i = 0; i < (sizeof(dummy)/sizeof(dummy[0])); i++) { dummy[i]++; } } static void * high_load (void *unused) { while (run) { add(); } return NULL; } static void * do_signal (void *unused) { while (run) { kill (getpid(), SIGUSR1); while (sem_wait(&sem) < 0 && errno == EINTR); } return NULL; } /* See tcc-doc.info */ #ifdef __BOUNDS_CHECKING_ON extern void __bound_checking (int no_check); #define BOUNDS_CHECKING_OFF __bound_checking(1) #define BOUNDS_CHECKING_ON __bound_checking(-1) #else #define BOUNDS_CHECKING_OFF #define BOUNDS_CHECKING_ON #endif static void real_signal_handler(int sig) { add(); sem_post (&sem); } static void signal_handler(int sig) { BOUNDS_CHECKING_OFF; real_signal_handler(sig); BOUNDS_CHECKING_ON; } int main (void) { int i; pthread_t id1, id2; struct sigaction act; struct timespec request; sigjmp_buf sj; sigset_t m; memset (&act, 0, sizeof (act)); act.sa_handler = signal_handler; act.sa_flags = 0; sigemptyset (&act.sa_mask); sigaction (SIGUSR1, &act, NULL); sem_init (&sem, 1, 0); pthread_create(&id1, NULL, high_load, NULL); pthread_create(&id2, NULL, do_signal, NULL); clock_gettime (CLOCK_MONOTONIC, &request); request.tv_sec += 1; request.tv_nsec += 0; printf ("start\n"); while (clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &request, NULL)) { } printf ("end\n"); run = 0; pthread_join(id1, NULL); pthread_join(id2, NULL); sem_destroy (&sem); sigemptyset (&m); sigprocmask (SIG_SETMASK, &m, NULL); if (sigsetjmp (sj, 0) == 0) { sigaddset (&m, SIGUSR1); sigprocmask (SIG_SETMASK, &m, NULL); siglongjmp (sj, 1); printf ("failed"); return 1; } sigprocmask (SIG_SETMASK, NULL, &m); if (!sigismember (&m, SIGUSR1)) printf ("failed"); return 0; }