1*c9945492SAndroid Build Coastguard Worker #include "pthread_impl.h"
2*c9945492SAndroid Build Coastguard Worker
3*c9945492SAndroid Build Coastguard Worker /* This lock primitive combines a flag (in the sign bit) and a
4*c9945492SAndroid Build Coastguard Worker * congestion count (= threads inside the critical section, CS) in a
5*c9945492SAndroid Build Coastguard Worker * single int that is accessed through atomic operations. The states
6*c9945492SAndroid Build Coastguard Worker * of the int for value x are:
7*c9945492SAndroid Build Coastguard Worker *
8*c9945492SAndroid Build Coastguard Worker * x == 0: unlocked and no thread inside the critical section
9*c9945492SAndroid Build Coastguard Worker *
10*c9945492SAndroid Build Coastguard Worker * x < 0: locked with a congestion of x-INT_MIN, including the thread
11*c9945492SAndroid Build Coastguard Worker * that holds the lock
12*c9945492SAndroid Build Coastguard Worker *
13*c9945492SAndroid Build Coastguard Worker * x > 0: unlocked with a congestion of x
14*c9945492SAndroid Build Coastguard Worker *
15*c9945492SAndroid Build Coastguard Worker * or in an equivalent formulation x is the congestion count or'ed
16*c9945492SAndroid Build Coastguard Worker * with INT_MIN as a lock flag.
17*c9945492SAndroid Build Coastguard Worker */
18*c9945492SAndroid Build Coastguard Worker
__lock(volatile int * l)19*c9945492SAndroid Build Coastguard Worker void __lock(volatile int *l)
20*c9945492SAndroid Build Coastguard Worker {
21*c9945492SAndroid Build Coastguard Worker int need_locks = libc.need_locks;
22*c9945492SAndroid Build Coastguard Worker if (!need_locks) return;
23*c9945492SAndroid Build Coastguard Worker /* fast path: INT_MIN for the lock, +1 for the congestion */
24*c9945492SAndroid Build Coastguard Worker int current = a_cas(l, 0, INT_MIN + 1);
25*c9945492SAndroid Build Coastguard Worker if (need_locks < 0) libc.need_locks = 0;
26*c9945492SAndroid Build Coastguard Worker if (!current) return;
27*c9945492SAndroid Build Coastguard Worker /* A first spin loop, for medium congestion. */
28*c9945492SAndroid Build Coastguard Worker for (unsigned i = 0; i < 10; ++i) {
29*c9945492SAndroid Build Coastguard Worker if (current < 0) current -= INT_MIN + 1;
30*c9945492SAndroid Build Coastguard Worker // assertion: current >= 0
31*c9945492SAndroid Build Coastguard Worker int val = a_cas(l, current, INT_MIN + (current + 1));
32*c9945492SAndroid Build Coastguard Worker if (val == current) return;
33*c9945492SAndroid Build Coastguard Worker current = val;
34*c9945492SAndroid Build Coastguard Worker }
35*c9945492SAndroid Build Coastguard Worker // Spinning failed, so mark ourselves as being inside the CS.
36*c9945492SAndroid Build Coastguard Worker current = a_fetch_add(l, 1) + 1;
37*c9945492SAndroid Build Coastguard Worker /* The main lock acquisition loop for heavy congestion. The only
38*c9945492SAndroid Build Coastguard Worker * change to the value performed inside that loop is a successful
39*c9945492SAndroid Build Coastguard Worker * lock via the CAS that acquires the lock. */
40*c9945492SAndroid Build Coastguard Worker for (;;) {
41*c9945492SAndroid Build Coastguard Worker /* We can only go into wait, if we know that somebody holds the
42*c9945492SAndroid Build Coastguard Worker * lock and will eventually wake us up, again. */
43*c9945492SAndroid Build Coastguard Worker if (current < 0) {
44*c9945492SAndroid Build Coastguard Worker __futexwait(l, current, 1);
45*c9945492SAndroid Build Coastguard Worker current -= INT_MIN + 1;
46*c9945492SAndroid Build Coastguard Worker }
47*c9945492SAndroid Build Coastguard Worker /* assertion: current > 0, the count includes us already. */
48*c9945492SAndroid Build Coastguard Worker int val = a_cas(l, current, INT_MIN + current);
49*c9945492SAndroid Build Coastguard Worker if (val == current) return;
50*c9945492SAndroid Build Coastguard Worker current = val;
51*c9945492SAndroid Build Coastguard Worker }
52*c9945492SAndroid Build Coastguard Worker }
53*c9945492SAndroid Build Coastguard Worker
__unlock(volatile int * l)54*c9945492SAndroid Build Coastguard Worker void __unlock(volatile int *l)
55*c9945492SAndroid Build Coastguard Worker {
56*c9945492SAndroid Build Coastguard Worker /* Check l[0] to see if we are multi-threaded. */
57*c9945492SAndroid Build Coastguard Worker if (l[0] < 0) {
58*c9945492SAndroid Build Coastguard Worker if (a_fetch_add(l, -(INT_MIN + 1)) != (INT_MIN + 1)) {
59*c9945492SAndroid Build Coastguard Worker __wake(l, 1, 1);
60*c9945492SAndroid Build Coastguard Worker }
61*c9945492SAndroid Build Coastguard Worker }
62*c9945492SAndroid Build Coastguard Worker }
63