Commit | Line | Data |
---|---|---|
acdb82a2 MJ |
1 | // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
2 | // | |
3 | // SPDX-License-Identifier: LGPL-2.1-or-later | |
4 | ||
49617de1 | 5 | /* |
49617de1 | 6 | * Userspace RCU library - sys_futex compatibility code |
49617de1 MD |
7 | */ |
8 | ||
9 | #include <stdio.h> | |
10 | #include <pthread.h> | |
11 | #include <signal.h> | |
49617de1 MD |
12 | #include <errno.h> |
13 | #include <poll.h> | |
6d841bc2 | 14 | #include <stdint.h> |
49617de1 MD |
15 | |
16 | #include <urcu/arch.h> | |
01477510 | 17 | #include <urcu/assert.h> |
41849996 | 18 | #include <urcu/futex.h> |
f4fe9309 | 19 | #include <urcu/system.h> |
49617de1 | 20 | |
5c02e37d MD |
21 | /* |
22 | * Using attribute "weak" for __urcu_compat_futex_lock and | |
23 | * __urcu_compat_futex_cond. Those are globally visible by the entire | |
24 | * program, even though many shared objects may have their own version. | |
25 | * The first version that gets loaded will be used by the entire program | |
26 | * (executable and all shared objects). | |
27 | */ | |
28 | ||
29 | __attribute__((weak)) | |
30 | pthread_mutex_t __urcu_compat_futex_lock = PTHREAD_MUTEX_INITIALIZER; | |
31 | __attribute__((weak)) | |
32 | pthread_cond_t __urcu_compat_futex_cond = PTHREAD_COND_INITIALIZER; | |
49617de1 MD |
33 | |
34 | /* | |
35 | * _NOT SIGNAL-SAFE_. pthread_cond is not signal-safe anyway. Though. | |
36 | * For now, timeout, uaddr2 and val3 are unused. | |
37 | * Waiter will relinquish the CPU until woken up. | |
38 | */ | |
39 | ||
6d841bc2 MD |
40 | int compat_futex_noasync(int32_t *uaddr, int op, int32_t val, |
41 | const struct timespec *timeout, int32_t *uaddr2, int32_t val3) | |
49617de1 | 42 | { |
54fd78ef | 43 | int ret = 0, lockret; |
49617de1 MD |
44 | |
45 | /* | |
46 | * Check if NULL. Don't let users expect that they are taken into | |
67ecffc0 | 47 | * account. |
49617de1 | 48 | */ |
01477510 FD |
49 | urcu_posix_assert(!timeout); |
50 | urcu_posix_assert(!uaddr2); | |
51 | urcu_posix_assert(!val3); | |
49617de1 MD |
52 | |
53 | /* | |
54 | * memory barriers to serialize with the previous uaddr modification. | |
55 | */ | |
5481ddb3 | 56 | cmm_smp_mb(); |
49617de1 | 57 | |
c8114d9b MD |
58 | lockret = pthread_mutex_lock(&__urcu_compat_futex_lock); |
59 | if (lockret) { | |
60 | errno = lockret; | |
b0a841b4 MD |
61 | ret = -1; |
62 | goto end; | |
63 | } | |
49617de1 MD |
64 | switch (op) { |
65 | case FUTEX_WAIT: | |
db21eff9 MD |
66 | /* |
67 | * Wait until *uaddr is changed to something else than "val". | |
68 | * Comparing *uaddr content against val figures out which | |
69 | * thread has been awakened. | |
70 | */ | |
f4fe9309 | 71 | while (CMM_LOAD_SHARED(*uaddr) == val) |
db21eff9 MD |
72 | pthread_cond_wait(&__urcu_compat_futex_cond, |
73 | &__urcu_compat_futex_lock); | |
49617de1 MD |
74 | break; |
75 | case FUTEX_WAKE: | |
db21eff9 MD |
76 | /* |
77 | * Each wake is sending a broadcast, thus attempting wakeup of | |
78 | * all awaiting threads, independently of their respective | |
79 | * uaddr. | |
80 | */ | |
5c02e37d | 81 | pthread_cond_broadcast(&__urcu_compat_futex_cond); |
49617de1 MD |
82 | break; |
83 | default: | |
b0a841b4 MD |
84 | errno = EINVAL; |
85 | ret = -1; | |
49617de1 | 86 | } |
c8114d9b MD |
87 | lockret = pthread_mutex_unlock(&__urcu_compat_futex_lock); |
88 | if (lockret) { | |
89 | errno = lockret; | |
b0a841b4 MD |
90 | ret = -1; |
91 | } | |
92 | end: | |
93 | return ret; | |
49617de1 MD |
94 | } |
95 | ||
96 | /* | |
97 | * _ASYNC SIGNAL-SAFE_. | |
98 | * For now, timeout, uaddr2 and val3 are unused. | |
99 | * Waiter will busy-loop trying to read the condition. | |
b2633d21 MD |
100 | * It is OK to use compat_futex_async() on a futex address on which |
101 | * futex() WAKE operations are also performed. | |
49617de1 MD |
102 | */ |
103 | ||
6d841bc2 MD |
104 | int compat_futex_async(int32_t *uaddr, int op, int32_t val, |
105 | const struct timespec *timeout, int32_t *uaddr2, int32_t val3) | |
49617de1 | 106 | { |
b0a841b4 MD |
107 | int ret = 0; |
108 | ||
49617de1 MD |
109 | /* |
110 | * Check if NULL. Don't let users expect that they are taken into | |
67ecffc0 | 111 | * account. |
49617de1 | 112 | */ |
01477510 FD |
113 | urcu_posix_assert(!timeout); |
114 | urcu_posix_assert(!uaddr2); | |
115 | urcu_posix_assert(!val3); | |
49617de1 MD |
116 | |
117 | /* | |
118 | * Ensure previous memory operations on uaddr have completed. | |
119 | */ | |
5481ddb3 | 120 | cmm_smp_mb(); |
49617de1 MD |
121 | |
122 | switch (op) { | |
123 | case FUTEX_WAIT: | |
b0a841b4 MD |
124 | while (CMM_LOAD_SHARED(*uaddr) == val) { |
125 | if (poll(NULL, 0, 10) < 0) { | |
126 | ret = -1; | |
127 | /* Keep poll errno. Caller handles EINTR. */ | |
128 | goto end; | |
129 | } | |
130 | } | |
49617de1 MD |
131 | break; |
132 | case FUTEX_WAKE: | |
133 | break; | |
134 | default: | |
b0a841b4 MD |
135 | errno = EINVAL; |
136 | ret = -1; | |
49617de1 | 137 | } |
b0a841b4 MD |
138 | end: |
139 | return ret; | |
49617de1 | 140 | } |