| 1 | #include <pthread_extra.h> |
| 2 | #include <time.h> |
| 3 | #include <errno.h> |
| 4 | |
| 5 | #define NSEC_PER_SEC (1000*1000*1000) |
| 6 | // timespec_normalise() from https://github.com/solemnwarning/timespec/ |
| 7 | struct timespec timespec_normalise(struct timespec ts) |
| 8 | { |
| 9 | while(ts.tv_nsec >= NSEC_PER_SEC) { |
| 10 | ++(ts.tv_sec); ts.tv_nsec -= NSEC_PER_SEC; |
| 11 | } |
| 12 | while(ts.tv_nsec <= -NSEC_PER_SEC) { |
| 13 | --(ts.tv_sec); ts.tv_nsec += NSEC_PER_SEC; |
| 14 | } |
| 15 | if(ts.tv_nsec < 0) { // Negative nanoseconds isn't valid according to POSIX. |
| 16 | --(ts.tv_sec); ts.tv_nsec = (NSEC_PER_SEC + ts.tv_nsec); |
| 17 | } |
| 18 | return ts; |
| 19 | } |
| 20 | |
| 21 | void pthread_nanosleep(struct timespec t) { |
| 22 | //Sleep calls on Linux get interrupted by signals, causing premature wake |
| 23 | //Pthread (un)pause is built using signals |
| 24 | //Therefore we need self-restarting sleep implementation |
| 25 | //IO timeouts are restarted by SA_RESTART, but sleeps do need explicit restart |
| 26 | //We also need to sleep using absolute time, because relative time is paused |
| 27 | //You should use this in any thread that gets (un)paused |
| 28 | |
| 29 | struct timespec wake; |
| 30 | clock_gettime(CLOCK_MONOTONIC, &wake); |
| 31 | |
| 32 | t = timespec_normalise(t); |
| 33 | wake.tv_sec += t.tv_sec; |
| 34 | wake.tv_nsec += t.tv_nsec; |
| 35 | wake = timespec_normalise(wake); |
| 36 | |
| 37 | while(clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wake, NULL)) if(errno!=EINTR) break; |
| 38 | return; |
| 39 | } |
| 40 | void pthread_nsleep(time_t s, long ns) { |
| 41 | struct timespec t; |
| 42 | t.tv_sec = s; |
| 43 | t.tv_nsec = ns; |
| 44 | pthread_nanosleep(t); |
| 45 | } |
| 46 | |
| 47 | void pthread_sleep(time_t s) { |
| 48 | pthread_nsleep(s, 0); |
| 49 | } |