Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust / compat_futex.c
CommitLineData
10544ee8 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-or-later
10544ee8
MD
3 *
4 * Copyright (c) 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
c0c0989a 6 * Userspace RCU library - sys_futex compatibility code
10544ee8
MD
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#include "futex.h"
20
21/*
22 * Using attribute "weak" for __lttng_ust_compat_futex_lock and
23 * __lttng_ust_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))
30pthread_mutex_t __lttng_ust_compat_futex_lock = PTHREAD_MUTEX_INITIALIZER;
31__attribute__((weak))
32pthread_cond_t __lttng_ust_compat_futex_cond = PTHREAD_COND_INITIALIZER;
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
40int lttng_ust_compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
41 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
42{
43 int ret = 0, lockret;
44
45 /*
46 * Check if NULL. Don't let users expect that they are taken into
47 * account.
48 */
49 assert(!timeout);
50 assert(!uaddr2);
51 assert(!val3);
52
53 /*
54 * memory barriers to serialize with the previous uaddr modification.
55 */
56 cmm_smp_mb();
57
58 lockret = pthread_mutex_lock(&__lttng_ust_compat_futex_lock);
59 if (lockret) {
60 errno = lockret;
61 ret = -1;
62 goto end;
63 }
64 switch (op) {
65 case FUTEX_WAIT:
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 */
71 while (CMM_LOAD_SHARED(*uaddr) == val)
72 pthread_cond_wait(&__lttng_ust_compat_futex_cond,
73 &__lttng_ust_compat_futex_lock);
74 break;
75 case FUTEX_WAKE:
76 /*
77 * Each wake is sending a broadcast, thus attempting wakeup of
78 * all awaiting threads, independently of their respective
79 * uaddr.
80 */
81 pthread_cond_broadcast(&__lttng_ust_compat_futex_cond);
82 break;
83 default:
84 errno = EINVAL;
85 ret = -1;
86 }
87 lockret = pthread_mutex_unlock(&__lttng_ust_compat_futex_lock);
88 if (lockret) {
89 errno = lockret;
90 ret = -1;
91 }
92end:
93 return ret;
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.
100 * It is OK to use compat_futex_async() on a futex address on which
101 * futex() WAKE operations are also performed.
102 */
103
104int lttng_ust_compat_futex_async(int32_t *uaddr, int op, int32_t val,
105 const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
106{
107 int ret = 0;
108
109 /*
110 * Check if NULL. Don't let users expect that they are taken into
111 * account.
112 */
113 assert(!timeout);
114 assert(!uaddr2);
115 assert(!val3);
116
117 /*
118 * Ensure previous memory operations on uaddr have completed.
119 */
120 cmm_smp_mb();
121
122 switch (op) {
123 case FUTEX_WAIT:
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 }
131 break;
132 case FUTEX_WAKE:
133 break;
134 default:
135 errno = EINVAL;
136 ret = -1;
137 }
138end:
139 return ret;
140}
This page took 0.02719 seconds and 4 git commands to generate.