1570af302Sopenharmony_ci#include <pthread.h>
2570af302Sopenharmony_ci#include <time.h>
3570af302Sopenharmony_ci#include <errno.h>
4570af302Sopenharmony_ci#include "futex.h"
5570af302Sopenharmony_ci#include "syscall.h"
6570af302Sopenharmony_ci#include "pthread_impl.h"
7570af302Sopenharmony_ci
8570af302Sopenharmony_ci#define IS32BIT(x) !((x)+0x80000000ULL>>32)
9570af302Sopenharmony_ci#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
10570af302Sopenharmony_ci
11570af302Sopenharmony_cistatic int __futex4_cp(volatile void *addr, int op, int val, const struct timespec *to)
12570af302Sopenharmony_ci{
13570af302Sopenharmony_ci	int r;
14570af302Sopenharmony_ci#ifdef __LITEOS_A__
15570af302Sopenharmony_ci	unsigned int useconds = 0xffffffffU;
16570af302Sopenharmony_ci	if (to) {
17570af302Sopenharmony_ci		useconds = (to->tv_sec * 1000000 + to->tv_nsec / 1000);
18570af302Sopenharmony_ci		if ((useconds == 0) && (to->tv_nsec != 0)) {
19570af302Sopenharmony_ci			useconds = 1;
20570af302Sopenharmony_ci		}
21570af302Sopenharmony_ci	}
22570af302Sopenharmony_ci
23570af302Sopenharmony_ci	r = __syscall_cp(SYS_futex, addr, op, val, useconds);
24570af302Sopenharmony_ci	if (r != -ENOSYS) return r;
25570af302Sopenharmony_ci	return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, useconds);
26570af302Sopenharmony_ci#else
27570af302Sopenharmony_ci#ifdef SYS_futex_time64
28570af302Sopenharmony_ci	time_t s = to ? to->tv_sec : 0;
29570af302Sopenharmony_ci	long ns = to ? to->tv_nsec : 0;
30570af302Sopenharmony_ci	r = -ENOSYS;
31570af302Sopenharmony_ci	if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
32570af302Sopenharmony_ci		r = __syscall_cp(SYS_futex_time64, addr, op, val,
33570af302Sopenharmony_ci			to ? ((long long[]){s, ns}) : 0);
34570af302Sopenharmony_ci	if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
35570af302Sopenharmony_ci	to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
36570af302Sopenharmony_ci#endif
37570af302Sopenharmony_ci	r = __syscall_cp(SYS_futex, addr, op, val, to);
38570af302Sopenharmony_ci	if (r != -ENOSYS) return r;
39570af302Sopenharmony_ci	return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to);
40570af302Sopenharmony_ci#endif
41570af302Sopenharmony_ci}
42570af302Sopenharmony_ci
43570af302Sopenharmony_cistatic volatile int dummy = 0;
44570af302Sopenharmony_ciweak_alias(dummy, __eintr_valid_flag);
45570af302Sopenharmony_ci
46570af302Sopenharmony_ciint __timedwait_cp(volatile int *addr, int val,
47570af302Sopenharmony_ci	clockid_t clk, const struct timespec *at, int priv)
48570af302Sopenharmony_ci{
49570af302Sopenharmony_ci	int r;
50570af302Sopenharmony_ci	struct timespec to, *top=0;
51570af302Sopenharmony_ci
52570af302Sopenharmony_ci	if (priv) priv = FUTEX_PRIVATE;
53570af302Sopenharmony_ci
54570af302Sopenharmony_ci	if (at) {
55570af302Sopenharmony_ci		if (at->tv_nsec >= 1000000000UL) return EINVAL;
56570af302Sopenharmony_ci		if (__clock_gettime(clk, &to)) return EINVAL;
57570af302Sopenharmony_ci		to.tv_sec = at->tv_sec - to.tv_sec;
58570af302Sopenharmony_ci		if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
59570af302Sopenharmony_ci			to.tv_sec--;
60570af302Sopenharmony_ci			to.tv_nsec += 1000000000;
61570af302Sopenharmony_ci		}
62570af302Sopenharmony_ci		if (to.tv_sec < 0) return ETIMEDOUT;
63570af302Sopenharmony_ci		top = &to;
64570af302Sopenharmony_ci	}
65570af302Sopenharmony_ci
66570af302Sopenharmony_ci	r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top);
67570af302Sopenharmony_ci	if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
68570af302Sopenharmony_ci	/* Mitigate bug in old kernels wrongly reporting EINTR for non-
69570af302Sopenharmony_ci	 * interrupting (SA_RESTART) signal handlers. This is only practical
70570af302Sopenharmony_ci	 * when NO interrupting signal handlers have been installed, and
71570af302Sopenharmony_ci	 * works by sigaction tracking whether that's the case. */
72570af302Sopenharmony_ci	if (r == EINTR && !__eintr_valid_flag) r = 0;
73570af302Sopenharmony_ci
74570af302Sopenharmony_ci	return r;
75570af302Sopenharmony_ci}
76570af302Sopenharmony_ci
77570af302Sopenharmony_ciint __timedwait(volatile int *addr, int val,
78570af302Sopenharmony_ci	clockid_t clk, const struct timespec *at, int priv)
79570af302Sopenharmony_ci{
80570af302Sopenharmony_ci	int cs, r;
81570af302Sopenharmony_ci	__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
82570af302Sopenharmony_ci	r = __timedwait_cp(addr, val, clk, at, priv);
83570af302Sopenharmony_ci	__pthread_setcancelstate(cs, 0);
84570af302Sopenharmony_ci	return r;
85570af302Sopenharmony_ci}
86