blob: 666093be98516a1c84b2997f075a8dbfcb797b2c [file] [log] [blame]
Rich Felkerec381af2011-08-02 21:11:36 -04001#include <pthread.h>
Rich Felker0b44a032011-02-12 00:22:29 -05002#include <time.h>
3#include <errno.h>
4#include "futex.h"
Rich Felker0b44a032011-02-12 00:22:29 -05005#include "syscall.h"
Rich Felker0fc317d2015-03-02 17:46:22 -05006#include "pthread_impl.h"
Rich Felkerfeee9892011-04-17 11:43:03 -04007
Rich Felker1492bdf2019-07-28 17:44:51 -04008#define IS32BIT(x) !((x)+0x80000000ULL>>32)
9#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
10
11static int __futex4_cp(volatile void *addr, int op, int val, const struct timespec *to)
12{
13 int r;
14#ifdef SYS_futex_time64
15 time_t s = to ? to->tv_sec : 0;
16 long ns = to ? to->tv_nsec : 0;
17 r = -ENOSYS;
18 if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
19 r = __syscall_cp(SYS_futex_time64, addr, op, val,
20 to ? ((long long[]){s, ns}) : 0);
21 if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
22 to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
23#endif
24 r = __syscall_cp(SYS_futex, addr, op, val, to);
25 if (r != -ENOSYS) return r;
26 return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to);
27}
28
Rich Felkera63c0102018-12-18 12:17:33 -050029static volatile int dummy = 0;
30weak_alias(dummy, __eintr_valid_flag);
31
Rich Felker0fc317d2015-03-02 17:46:22 -050032int __timedwait_cp(volatile int *addr, int val,
33 clockid_t clk, const struct timespec *at, int priv)
Rich Felkerec381af2011-08-02 21:11:36 -040034{
Rich Felker0fc317d2015-03-02 17:46:22 -050035 int r;
Rich Felkerec381af2011-08-02 21:11:36 -040036 struct timespec to, *top=0;
37
Jens Gustedtd906fa32017-06-24 10:18:05 +020038 if (priv) priv = FUTEX_PRIVATE;
Rich Felkerbc09d582014-08-15 23:54:52 -040039
Rich Felkerb3c08a12011-08-07 11:14:32 -040040 if (at) {
41 if (at->tv_nsec >= 1000000000UL) return EINVAL;
Jens Gustedtdf7d0df2014-09-01 00:46:23 +020042 if (__clock_gettime(clk, &to)) return EINVAL;
Rich Felkerb3c08a12011-08-07 11:14:32 -040043 to.tv_sec = at->tv_sec - to.tv_sec;
44 if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
45 to.tv_sec--;
46 to.tv_nsec += 1000000000;
47 }
48 if (to.tv_sec < 0) return ETIMEDOUT;
49 top = &to;
Rich Felkerec381af2011-08-02 21:11:36 -040050 }
Rich Felkerb3c08a12011-08-07 11:14:32 -040051
Rich Felker1492bdf2019-07-28 17:44:51 -040052 r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top);
Rich Felker76ca7a52015-02-27 23:25:45 -050053 if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
Rich Felkera63c0102018-12-18 12:17:33 -050054 /* Mitigate bug in old kernels wrongly reporting EINTR for non-
55 * interrupting (SA_RESTART) signal handlers. This is only practical
56 * when NO interrupting signal handlers have been installed, and
57 * works by sigaction tracking whether that's the case. */
58 if (r == EINTR && !__eintr_valid_flag) r = 0;
Rich Felkerb3c08a12011-08-07 11:14:32 -040059
Rich Felker0fc317d2015-03-02 17:46:22 -050060 return r;
61}
Rich Felkerb3c08a12011-08-07 11:14:32 -040062
Rich Felker0fc317d2015-03-02 17:46:22 -050063int __timedwait(volatile int *addr, int val,
64 clockid_t clk, const struct timespec *at, int priv)
65{
66 int cs, r;
67 __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
68 r = __timedwait_cp(addr, val, clk, at, priv);
69 __pthread_setcancelstate(cs, 0);
Rich Felkerec381af2011-08-02 21:11:36 -040070 return r;
Rich Felker0b44a032011-02-12 00:22:29 -050071}