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