xref: /aosp_15_r20/external/mesa3d/src/util/simple_mtx.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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