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