1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2015 Intel
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*61046927SAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
9*61046927SAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*61046927SAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*61046927SAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*61046927SAndroid Build Coastguard Worker * IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #ifndef _SIMPLE_MTX_H
25*61046927SAndroid Build Coastguard Worker #define _SIMPLE_MTX_H
26*61046927SAndroid Build Coastguard Worker
27*61046927SAndroid Build Coastguard Worker #include "util/futex.h"
28*61046927SAndroid Build Coastguard Worker #include "util/macros.h"
29*61046927SAndroid Build Coastguard Worker #include "util/u_call_once.h"
30*61046927SAndroid Build Coastguard Worker #include "u_atomic.h"
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker #if UTIL_FUTEX_SUPPORTED
33*61046927SAndroid Build Coastguard Worker #if defined(HAVE_VALGRIND) && !defined(NDEBUG)
34*61046927SAndroid Build Coastguard Worker # include <valgrind.h>
35*61046927SAndroid Build Coastguard Worker # include <helgrind.h>
36*61046927SAndroid Build Coastguard Worker # define HG(x) x
37*61046927SAndroid Build Coastguard Worker #else
38*61046927SAndroid Build Coastguard Worker # define HG(x)
39*61046927SAndroid Build Coastguard Worker #endif
40*61046927SAndroid Build Coastguard Worker #else /* !UTIL_FUTEX_SUPPORTED */
41*61046927SAndroid Build Coastguard Worker # include "c11/threads.h"
42*61046927SAndroid Build Coastguard Worker #endif /* UTIL_FUTEX_SUPPORTED */
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker #ifdef __cplusplus
45*61046927SAndroid Build Coastguard Worker extern "C" {
46*61046927SAndroid Build Coastguard Worker #endif
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker #if UTIL_FUTEX_SUPPORTED
49*61046927SAndroid Build Coastguard Worker
50*61046927SAndroid Build Coastguard Worker /* mtx_t - Fast, simple mutex
51*61046927SAndroid Build Coastguard Worker *
52*61046927SAndroid Build Coastguard Worker * While modern pthread mutexes are very fast (implemented using futex), they
53*61046927SAndroid Build Coastguard Worker * still incur a call to an external DSO and overhead of the generality and
54*61046927SAndroid Build Coastguard Worker * features of pthread mutexes. Most mutexes in mesa only needs lock/unlock,
55*61046927SAndroid Build Coastguard Worker * and the idea here is that we can inline the atomic operation and make the
56*61046927SAndroid Build Coastguard Worker * fast case just two intructions. Mutexes are subtle and finicky to
57*61046927SAndroid Build Coastguard Worker * implement, so we carefully copy the implementation from Ulrich Dreppers
58*61046927SAndroid Build Coastguard Worker * well-written and well-reviewed paper:
59*61046927SAndroid Build Coastguard Worker *
60*61046927SAndroid Build Coastguard Worker * "Futexes Are Tricky"
61*61046927SAndroid Build Coastguard Worker * http://www.akkadia.org/drepper/futex.pdf
62*61046927SAndroid Build Coastguard Worker *
63*61046927SAndroid Build Coastguard Worker * We implement "mutex3", which gives us a mutex that has no syscalls on
64*61046927SAndroid Build Coastguard Worker * uncontended lock or unlock. Further, the uncontended case boils down to a
65*61046927SAndroid Build Coastguard Worker * locked cmpxchg and an untaken branch, the uncontended unlock is just a
66*61046927SAndroid Build Coastguard Worker * locked decr and an untaken branch. We use __builtin_expect() to indicate
67*61046927SAndroid Build Coastguard Worker * that contention is unlikely so that gcc will put the contention code out of
68*61046927SAndroid Build Coastguard Worker * the main code flow.
69*61046927SAndroid Build Coastguard Worker *
70*61046927SAndroid Build Coastguard Worker * A fast mutex only supports lock/unlock, can't be recursive or used with
71*61046927SAndroid Build Coastguard Worker * condition variables.
72*61046927SAndroid Build Coastguard Worker */
73*61046927SAndroid Build Coastguard Worker
74*61046927SAndroid Build Coastguard Worker typedef struct {
75*61046927SAndroid Build Coastguard Worker uint32_t val;
76*61046927SAndroid Build Coastguard Worker } simple_mtx_t;
77*61046927SAndroid Build Coastguard Worker
78*61046927SAndroid Build Coastguard Worker #define SIMPLE_MTX_INITIALIZER { 0 }
79*61046927SAndroid Build Coastguard Worker
80*61046927SAndroid Build Coastguard Worker #define _SIMPLE_MTX_INVALID_VALUE 0xd0d0d0d0
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker static inline void
simple_mtx_init(simple_mtx_t * mtx,ASSERTED int type)83*61046927SAndroid Build Coastguard Worker simple_mtx_init(simple_mtx_t *mtx, ASSERTED int type)
84*61046927SAndroid Build Coastguard Worker {
85*61046927SAndroid Build Coastguard Worker assert(type == mtx_plain);
86*61046927SAndroid Build Coastguard Worker
87*61046927SAndroid Build Coastguard Worker mtx->val = 0;
88*61046927SAndroid Build Coastguard Worker
89*61046927SAndroid Build Coastguard Worker HG(ANNOTATE_RWLOCK_CREATE(mtx));
90*61046927SAndroid Build Coastguard Worker }
91*61046927SAndroid Build Coastguard Worker
92*61046927SAndroid Build Coastguard Worker static inline void
simple_mtx_destroy(ASSERTED simple_mtx_t * mtx)93*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(ASSERTED simple_mtx_t *mtx)
94*61046927SAndroid Build Coastguard Worker {
95*61046927SAndroid Build Coastguard Worker HG(ANNOTATE_RWLOCK_DESTROY(mtx));
96*61046927SAndroid Build Coastguard Worker #ifndef NDEBUG
97*61046927SAndroid Build Coastguard Worker mtx->val = _SIMPLE_MTX_INVALID_VALUE;
98*61046927SAndroid Build Coastguard Worker #endif
99*61046927SAndroid Build Coastguard Worker }
100*61046927SAndroid Build Coastguard Worker
101*61046927SAndroid Build Coastguard Worker static inline void
simple_mtx_lock(simple_mtx_t * mtx)102*61046927SAndroid Build Coastguard Worker simple_mtx_lock(simple_mtx_t *mtx)
103*61046927SAndroid Build Coastguard Worker {
104*61046927SAndroid Build Coastguard Worker uint32_t c;
105*61046927SAndroid Build Coastguard Worker
106*61046927SAndroid Build Coastguard Worker c = p_atomic_cmpxchg(&mtx->val, 0, 1);
107*61046927SAndroid Build Coastguard Worker
108*61046927SAndroid Build Coastguard Worker assert(c != _SIMPLE_MTX_INVALID_VALUE);
109*61046927SAndroid Build Coastguard Worker
110*61046927SAndroid Build Coastguard Worker if (__builtin_expect(c != 0, 0)) {
111*61046927SAndroid Build Coastguard Worker if (c != 2)
112*61046927SAndroid Build Coastguard Worker c = p_atomic_xchg(&mtx->val, 2);
113*61046927SAndroid Build Coastguard Worker while (c != 0) {
114*61046927SAndroid Build Coastguard Worker futex_wait(&mtx->val, 2, NULL);
115*61046927SAndroid Build Coastguard Worker c = p_atomic_xchg(&mtx->val, 2);
116*61046927SAndroid Build Coastguard Worker }
117*61046927SAndroid Build Coastguard Worker }
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker HG(ANNOTATE_RWLOCK_ACQUIRED(mtx, 1));
120*61046927SAndroid Build Coastguard Worker }
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker static inline void
simple_mtx_unlock(simple_mtx_t * mtx)123*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(simple_mtx_t *mtx)
124*61046927SAndroid Build Coastguard Worker {
125*61046927SAndroid Build Coastguard Worker uint32_t c;
126*61046927SAndroid Build Coastguard Worker
127*61046927SAndroid Build Coastguard Worker HG(ANNOTATE_RWLOCK_RELEASED(mtx, 1));
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker c = p_atomic_fetch_add(&mtx->val, -1);
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker assert(c != _SIMPLE_MTX_INVALID_VALUE);
132*61046927SAndroid Build Coastguard Worker
133*61046927SAndroid Build Coastguard Worker if (__builtin_expect(c != 1, 0)) {
134*61046927SAndroid Build Coastguard Worker mtx->val = 0;
135*61046927SAndroid Build Coastguard Worker futex_wake(&mtx->val, 1);
136*61046927SAndroid Build Coastguard Worker }
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker static inline void
simple_mtx_assert_locked(simple_mtx_t * mtx)140*61046927SAndroid Build Coastguard Worker simple_mtx_assert_locked(simple_mtx_t *mtx)
141*61046927SAndroid Build Coastguard Worker {
142*61046927SAndroid Build Coastguard Worker assert(mtx->val);
143*61046927SAndroid Build Coastguard Worker }
144*61046927SAndroid Build Coastguard Worker
145*61046927SAndroid Build Coastguard Worker #else /* !UTIL_FUTEX_SUPPORTED */
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker typedef struct simple_mtx_t {
148*61046927SAndroid Build Coastguard Worker util_once_flag flag;
149*61046927SAndroid Build Coastguard Worker mtx_t mtx;
150*61046927SAndroid Build Coastguard Worker } simple_mtx_t;
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker #define SIMPLE_MTX_INITIALIZER { UTIL_ONCE_FLAG_INIT }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker void _simple_mtx_plain_init_once(simple_mtx_t *mtx);
155*61046927SAndroid Build Coastguard Worker
156*61046927SAndroid Build Coastguard Worker static inline void
157*61046927SAndroid Build Coastguard Worker _simple_mtx_init_with_once(simple_mtx_t *mtx)
158*61046927SAndroid Build Coastguard Worker {
159*61046927SAndroid Build Coastguard Worker util_call_once_data(&mtx->flag,
160*61046927SAndroid Build Coastguard Worker (util_call_once_data_func)_simple_mtx_plain_init_once, mtx);
161*61046927SAndroid Build Coastguard Worker }
162*61046927SAndroid Build Coastguard Worker
163*61046927SAndroid Build Coastguard Worker void
164*61046927SAndroid Build Coastguard Worker simple_mtx_init(simple_mtx_t *mtx, int type);
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker void
167*61046927SAndroid Build Coastguard Worker simple_mtx_destroy(simple_mtx_t *mtx);
168*61046927SAndroid Build Coastguard Worker
169*61046927SAndroid Build Coastguard Worker static inline void
170*61046927SAndroid Build Coastguard Worker simple_mtx_lock(simple_mtx_t *mtx)
171*61046927SAndroid Build Coastguard Worker {
172*61046927SAndroid Build Coastguard Worker _simple_mtx_init_with_once(mtx);
173*61046927SAndroid Build Coastguard Worker mtx_lock(&mtx->mtx);
174*61046927SAndroid Build Coastguard Worker }
175*61046927SAndroid Build Coastguard Worker
176*61046927SAndroid Build Coastguard Worker static inline void
177*61046927SAndroid Build Coastguard Worker simple_mtx_unlock(simple_mtx_t *mtx)
178*61046927SAndroid Build Coastguard Worker {
179*61046927SAndroid Build Coastguard Worker _simple_mtx_init_with_once(mtx);
180*61046927SAndroid Build Coastguard Worker mtx_unlock(&mtx->mtx);
181*61046927SAndroid Build Coastguard Worker }
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker static inline void
184*61046927SAndroid Build Coastguard Worker simple_mtx_assert_locked(simple_mtx_t *mtx)
185*61046927SAndroid Build Coastguard Worker {
186*61046927SAndroid Build Coastguard Worker #ifndef NDEBUG
187*61046927SAndroid Build Coastguard Worker _simple_mtx_init_with_once(mtx);
188*61046927SAndroid Build Coastguard Worker /* NOTE: this would not work for recursive mutexes, but
189*61046927SAndroid Build Coastguard Worker * mtx_t doesn't support those
190*61046927SAndroid Build Coastguard Worker */
191*61046927SAndroid Build Coastguard Worker int ret = mtx_trylock(&mtx->mtx);
192*61046927SAndroid Build Coastguard Worker assert(ret == thrd_busy);
193*61046927SAndroid Build Coastguard Worker if (ret == thrd_success)
194*61046927SAndroid Build Coastguard Worker mtx_unlock(&mtx->mtx);
195*61046927SAndroid Build Coastguard Worker #else
196*61046927SAndroid Build Coastguard Worker (void)mtx;
197*61046927SAndroid Build Coastguard Worker #endif
198*61046927SAndroid Build Coastguard Worker }
199*61046927SAndroid Build Coastguard Worker
200*61046927SAndroid Build Coastguard Worker #endif /* UTIL_FUTEX_SUPPORTED */
201*61046927SAndroid Build Coastguard Worker
202*61046927SAndroid Build Coastguard Worker #ifdef __cplusplus
203*61046927SAndroid Build Coastguard Worker }
204*61046927SAndroid Build Coastguard Worker #endif
205*61046927SAndroid Build Coastguard Worker
206*61046927SAndroid Build Coastguard Worker #endif /* _SIMPLE_MTX_H */
207