xref: /aosp_15_r20/bionic/libc/private/bionic_lock.h (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker  * are met:
8*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker  *  * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker  *    the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker  *    distribution.
14*8d67ca89SAndroid Build Coastguard Worker  *
15*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker  */
28*8d67ca89SAndroid Build Coastguard Worker 
29*8d67ca89SAndroid Build Coastguard Worker #pragma once
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include <stdatomic.h>
32*8d67ca89SAndroid Build Coastguard Worker #include "private/bionic_futex.h"
33*8d67ca89SAndroid Build Coastguard Worker #include "platform/bionic/macros.h"
34*8d67ca89SAndroid Build Coastguard Worker 
35*8d67ca89SAndroid Build Coastguard Worker // Lock is used in places like pthread_rwlock_t, which can be initialized without calling
36*8d67ca89SAndroid Build Coastguard Worker // an initialization function. So make sure Lock can be initialized by setting its memory to 0.
37*8d67ca89SAndroid Build Coastguard Worker class Lock {
38*8d67ca89SAndroid Build Coastguard Worker  private:
39*8d67ca89SAndroid Build Coastguard Worker   enum LockState {
40*8d67ca89SAndroid Build Coastguard Worker     Unlocked = 0,
41*8d67ca89SAndroid Build Coastguard Worker     LockedWithoutWaiter,
42*8d67ca89SAndroid Build Coastguard Worker     LockedWithWaiter,
43*8d67ca89SAndroid Build Coastguard Worker   };
44*8d67ca89SAndroid Build Coastguard Worker   _Atomic(LockState) state;
45*8d67ca89SAndroid Build Coastguard Worker   bool process_shared;
46*8d67ca89SAndroid Build Coastguard Worker 
47*8d67ca89SAndroid Build Coastguard Worker  public:
init(bool process_shared)48*8d67ca89SAndroid Build Coastguard Worker   void init(bool process_shared) {
49*8d67ca89SAndroid Build Coastguard Worker     atomic_store_explicit(&state, Unlocked, memory_order_relaxed);
50*8d67ca89SAndroid Build Coastguard Worker     this->process_shared = process_shared;
51*8d67ca89SAndroid Build Coastguard Worker   }
52*8d67ca89SAndroid Build Coastguard Worker 
trylock()53*8d67ca89SAndroid Build Coastguard Worker   bool trylock() {
54*8d67ca89SAndroid Build Coastguard Worker     LockState old_state = Unlocked;
55*8d67ca89SAndroid Build Coastguard Worker     return __predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
56*8d67ca89SAndroid Build Coastguard Worker                         LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed));
57*8d67ca89SAndroid Build Coastguard Worker   }
58*8d67ca89SAndroid Build Coastguard Worker 
lock()59*8d67ca89SAndroid Build Coastguard Worker   void lock() {
60*8d67ca89SAndroid Build Coastguard Worker     LockState old_state = Unlocked;
61*8d67ca89SAndroid Build Coastguard Worker     if (__predict_true(atomic_compare_exchange_strong_explicit(&state, &old_state,
62*8d67ca89SAndroid Build Coastguard Worker                          LockedWithoutWaiter, memory_order_acquire, memory_order_relaxed))) {
63*8d67ca89SAndroid Build Coastguard Worker       return;
64*8d67ca89SAndroid Build Coastguard Worker     }
65*8d67ca89SAndroid Build Coastguard Worker     while (atomic_exchange_explicit(&state, LockedWithWaiter, memory_order_acquire) != Unlocked) {
66*8d67ca89SAndroid Build Coastguard Worker       // TODO: As the critical section is brief, it is a better choice to spin a few times befor sleeping.
67*8d67ca89SAndroid Build Coastguard Worker       __futex_wait_ex(&state, process_shared, LockedWithWaiter);
68*8d67ca89SAndroid Build Coastguard Worker     }
69*8d67ca89SAndroid Build Coastguard Worker     return;
70*8d67ca89SAndroid Build Coastguard Worker   }
71*8d67ca89SAndroid Build Coastguard Worker 
unlock()72*8d67ca89SAndroid Build Coastguard Worker   void unlock() {
73*8d67ca89SAndroid Build Coastguard Worker     bool shared = process_shared; /* cache to local variable */
74*8d67ca89SAndroid Build Coastguard Worker     if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) {
75*8d67ca89SAndroid Build Coastguard Worker       // The Lock object may have been deallocated between the atomic exchange and the futex wake
76*8d67ca89SAndroid Build Coastguard Worker       // call, so avoid accessing any fields of Lock here. In that case, the wake call may target
77*8d67ca89SAndroid Build Coastguard Worker       // unmapped memory or trigger a spurious futex wakeup. The same situation happens with
78*8d67ca89SAndroid Build Coastguard Worker       // pthread mutexes. References:
79*8d67ca89SAndroid Build Coastguard Worker       //  - https://lkml.org/lkml/2014/11/27/472
80*8d67ca89SAndroid Build Coastguard Worker       //  - http://austingroupbugs.net/view.php?id=811#c2267
81*8d67ca89SAndroid Build Coastguard Worker       __futex_wake_ex(&state, shared, 1);
82*8d67ca89SAndroid Build Coastguard Worker     }
83*8d67ca89SAndroid Build Coastguard Worker   }
84*8d67ca89SAndroid Build Coastguard Worker };
85*8d67ca89SAndroid Build Coastguard Worker 
86*8d67ca89SAndroid Build Coastguard Worker class LockGuard {
87*8d67ca89SAndroid Build Coastguard Worker  public:
LockGuard(Lock & lock)88*8d67ca89SAndroid Build Coastguard Worker   explicit LockGuard(Lock& lock) : lock_(lock) {
89*8d67ca89SAndroid Build Coastguard Worker     lock_.lock();
90*8d67ca89SAndroid Build Coastguard Worker   }
~LockGuard()91*8d67ca89SAndroid Build Coastguard Worker   ~LockGuard() {
92*8d67ca89SAndroid Build Coastguard Worker     lock_.unlock();
93*8d67ca89SAndroid Build Coastguard Worker   }
94*8d67ca89SAndroid Build Coastguard Worker 
95*8d67ca89SAndroid Build Coastguard Worker   BIONIC_DISALLOW_COPY_AND_ASSIGN(LockGuard);
96*8d67ca89SAndroid Build Coastguard Worker 
97*8d67ca89SAndroid Build Coastguard Worker  private:
98*8d67ca89SAndroid Build Coastguard Worker   Lock& lock_;
99*8d67ca89SAndroid Build Coastguard Worker };
100