]>
Commit | Line | Data |
---|---|---|
320054e8 DG |
1 | #include "pthread_impl.h" |
2 | ||
33c3753c | 3 | #ifdef __wasilibc_unmodified_upstream |
79a9b408 DG |
4 | #define IS32BIT(x) !((x)+0x80000000ULL>>32) |
5 | #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) | |
6 | ||
7 | static int __futex4(volatile void *addr, int op, int val, const struct timespec *to) | |
8 | { | |
9 | #ifdef SYS_futex_time64 | |
10 | time_t s = to ? to->tv_sec : 0; | |
11 | long ns = to ? to->tv_nsec : 0; | |
12 | int r = -ENOSYS; | |
13 | if (SYS_futex == SYS_futex_time64 || !IS32BIT(s)) | |
14 | r = __syscall(SYS_futex_time64, addr, op, val, | |
15 | to ? ((long long[]){s, ns}) : 0); | |
16 | if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r; | |
17 | to = to ? (void *)(long[]){CLAMP(s), ns} : 0; | |
18 | #endif | |
19 | return __syscall(SYS_futex, addr, op, val, to); | |
20 | } | |
21 | ||
f41256b6 DG |
22 | static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct timespec *restrict at) |
23 | { | |
24 | int type = m->_m_type; | |
25 | int priv = (type & 128) ^ 128; | |
26 | pthread_t self = __pthread_self(); | |
27 | int e; | |
28 | ||
29 | if (!priv) self->robust_list.pending = &m->_m_next; | |
30 | ||
79a9b408 | 31 | do e = -__futex4(&m->_m_lock, FUTEX_LOCK_PI|priv, 0, at); |
f41256b6 DG |
32 | while (e==EINTR); |
33 | if (e) self->robust_list.pending = 0; | |
34 | ||
35 | switch (e) { | |
36 | case 0: | |
37 | /* Catch spurious success for non-robust mutexes. */ | |
38 | if (!(type&4) && ((m->_m_lock & 0x40000000) || m->_m_waiters)) { | |
39 | a_store(&m->_m_waiters, -1); | |
40 | __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv); | |
41 | self->robust_list.pending = 0; | |
42 | break; | |
43 | } | |
44 | /* Signal to trylock that we already have the lock. */ | |
45 | m->_m_count = -1; | |
46 | return __pthread_mutex_trylock(m); | |
47 | case ETIMEDOUT: | |
48 | return e; | |
49 | case EDEADLK: | |
50 | if ((type&3) == PTHREAD_MUTEX_ERRORCHECK) return e; | |
51 | } | |
52 | do e = __timedwait(&(int){0}, 0, CLOCK_REALTIME, at, 1); | |
53 | while (e != ETIMEDOUT); | |
54 | return e; | |
55 | } | |
33c3753c | 56 | #endif |
f41256b6 | 57 | |
320054e8 DG |
58 | int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at) |
59 | { | |
60 | if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL | |
61 | && !a_cas(&m->_m_lock, 0, EBUSY)) | |
62 | return 0; | |
63 | ||
64 | int type = m->_m_type; | |
65 | int r, t, priv = (type & 128) ^ 128; | |
66 | ||
f41256b6 | 67 | r = __pthread_mutex_trylock(m); |
320054e8 | 68 | if (r != EBUSY) return r; |
f41256b6 | 69 | |
33c3753c | 70 | #ifdef __wasilibc_unmodified_upstream |
f41256b6 | 71 | if (type&8) return pthread_mutex_timedlock_pi(m, at); |
33c3753c AB |
72 | #endif |
73 | ||
320054e8 DG |
74 | int spins = 100; |
75 | while (spins-- && m->_m_lock && !m->_m_waiters) a_spin(); | |
76 | ||
77 | while ((r=__pthread_mutex_trylock(m)) == EBUSY) { | |
f41256b6 DG |
78 | r = m->_m_lock; |
79 | int own = r & 0x3fffffff; | |
80 | if (!own && (!r || (type&4))) | |
320054e8 DG |
81 | continue; |
82 | if ((type&3) == PTHREAD_MUTEX_ERRORCHECK | |
f41256b6 | 83 | && own == __pthread_self()->tid) |
320054e8 DG |
84 | return EDEADLK; |
85 | ||
86 | a_inc(&m->_m_waiters); | |
87 | t = r | 0x80000000; | |
88 | a_cas(&m->_m_lock, r, t); | |
89 | r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, priv); | |
90 | a_dec(&m->_m_waiters); | |
91 | if (r && r != EINTR) break; | |
92 | } | |
93 | return r; | |
94 | } | |
95 | ||
96 | weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock); |