xref: /aosp_15_r20/external/musl/src/thread/__timedwait.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include <pthread.h>
2*c9945492SAndroid Build Coastguard Worker #include <time.h>
3*c9945492SAndroid Build Coastguard Worker #include <errno.h>
4*c9945492SAndroid Build Coastguard Worker #include "futex.h"
5*c9945492SAndroid Build Coastguard Worker #include "syscall.h"
6*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
7*c9945492SAndroid Build Coastguard Worker 
8*c9945492SAndroid Build Coastguard Worker #define IS32BIT(x) !((x)+0x80000000ULL>>32)
9*c9945492SAndroid Build Coastguard Worker #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
10*c9945492SAndroid Build Coastguard Worker 
__futex4_cp(volatile void * addr,int op,int val,const struct timespec * to)11*c9945492SAndroid Build Coastguard Worker static int __futex4_cp(volatile void *addr, int op, int val, const struct timespec *to)
12*c9945492SAndroid Build Coastguard Worker {
13*c9945492SAndroid Build Coastguard Worker 	int r;
14*c9945492SAndroid Build Coastguard Worker #ifdef SYS_futex_time64
15*c9945492SAndroid Build Coastguard Worker 	time_t s = to ? to->tv_sec : 0;
16*c9945492SAndroid Build Coastguard Worker 	long ns = to ? to->tv_nsec : 0;
17*c9945492SAndroid Build Coastguard Worker 	r = -ENOSYS;
18*c9945492SAndroid Build Coastguard Worker 	if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
19*c9945492SAndroid Build Coastguard Worker 		r = __syscall_cp(SYS_futex_time64, addr, op, val,
20*c9945492SAndroid Build Coastguard Worker 			to ? ((long long[]){s, ns}) : 0);
21*c9945492SAndroid Build Coastguard Worker 	if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
22*c9945492SAndroid Build Coastguard Worker 	to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
23*c9945492SAndroid Build Coastguard Worker #endif
24*c9945492SAndroid Build Coastguard Worker 	r = __syscall_cp(SYS_futex, addr, op, val, to);
25*c9945492SAndroid Build Coastguard Worker 	if (r != -ENOSYS) return r;
26*c9945492SAndroid Build Coastguard Worker 	return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to);
27*c9945492SAndroid Build Coastguard Worker }
28*c9945492SAndroid Build Coastguard Worker 
29*c9945492SAndroid Build Coastguard Worker static volatile int dummy = 0;
30*c9945492SAndroid Build Coastguard Worker weak_alias(dummy, __eintr_valid_flag);
31*c9945492SAndroid Build Coastguard Worker 
__timedwait_cp(volatile int * addr,int val,clockid_t clk,const struct timespec * at,int priv)32*c9945492SAndroid Build Coastguard Worker int __timedwait_cp(volatile int *addr, int val,
33*c9945492SAndroid Build Coastguard Worker 	clockid_t clk, const struct timespec *at, int priv)
34*c9945492SAndroid Build Coastguard Worker {
35*c9945492SAndroid Build Coastguard Worker 	int r;
36*c9945492SAndroid Build Coastguard Worker 	struct timespec to, *top=0;
37*c9945492SAndroid Build Coastguard Worker 
38*c9945492SAndroid Build Coastguard Worker 	if (priv) priv = FUTEX_PRIVATE;
39*c9945492SAndroid Build Coastguard Worker 
40*c9945492SAndroid Build Coastguard Worker 	if (at) {
41*c9945492SAndroid Build Coastguard Worker 		if (at->tv_nsec >= 1000000000UL) return EINVAL;
42*c9945492SAndroid Build Coastguard Worker 		if (__clock_gettime(clk, &to)) return EINVAL;
43*c9945492SAndroid Build Coastguard Worker 		to.tv_sec = at->tv_sec - to.tv_sec;
44*c9945492SAndroid Build Coastguard Worker 		if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
45*c9945492SAndroid Build Coastguard Worker 			to.tv_sec--;
46*c9945492SAndroid Build Coastguard Worker 			to.tv_nsec += 1000000000;
47*c9945492SAndroid Build Coastguard Worker 		}
48*c9945492SAndroid Build Coastguard Worker 		if (to.tv_sec < 0) return ETIMEDOUT;
49*c9945492SAndroid Build Coastguard Worker 		top = &to;
50*c9945492SAndroid Build Coastguard Worker 	}
51*c9945492SAndroid Build Coastguard Worker 
52*c9945492SAndroid Build Coastguard Worker 	r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top);
53*c9945492SAndroid Build Coastguard Worker 	if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
54*c9945492SAndroid Build Coastguard Worker 	/* Mitigate bug in old kernels wrongly reporting EINTR for non-
55*c9945492SAndroid Build Coastguard Worker 	 * interrupting (SA_RESTART) signal handlers. This is only practical
56*c9945492SAndroid Build Coastguard Worker 	 * when NO interrupting signal handlers have been installed, and
57*c9945492SAndroid Build Coastguard Worker 	 * works by sigaction tracking whether that's the case. */
58*c9945492SAndroid Build Coastguard Worker 	if (r == EINTR && !__eintr_valid_flag) r = 0;
59*c9945492SAndroid Build Coastguard Worker 
60*c9945492SAndroid Build Coastguard Worker 	return r;
61*c9945492SAndroid Build Coastguard Worker }
62*c9945492SAndroid Build Coastguard Worker 
__timedwait(volatile int * addr,int val,clockid_t clk,const struct timespec * at,int priv)63*c9945492SAndroid Build Coastguard Worker int __timedwait(volatile int *addr, int val,
64*c9945492SAndroid Build Coastguard Worker 	clockid_t clk, const struct timespec *at, int priv)
65*c9945492SAndroid Build Coastguard Worker {
66*c9945492SAndroid Build Coastguard Worker 	int cs, r;
67*c9945492SAndroid Build Coastguard Worker 	__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
68*c9945492SAndroid Build Coastguard Worker 	r = __timedwait_cp(addr, val, clk, at, priv);
69*c9945492SAndroid Build Coastguard Worker 	__pthread_setcancelstate(cs, 0);
70*c9945492SAndroid Build Coastguard Worker 	return r;
71*c9945492SAndroid Build Coastguard Worker }
72