• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_LIBPANDABASE_PBASE_OS_UNIX_FUTEX_FMUTEX_H
17 #define PANDA_LIBPANDABASE_PBASE_OS_UNIX_FUTEX_FMUTEX_H
18 
19 #ifdef MC_ON
20 #include <assert.h>
21 #include <limits.h>
22 #include <pthread.h>
23 #include <stdatomic.h>
24 #define THREAD_ID pthread_t
25 #define GET_CURRENT_THREAD pthread_self()
26 #define ATOMIC(type) _Atomic type
27 #define ATOMIC_INT atomic_int
28 #define ATOMIC_STORE(addr, val, mem) atomic_store_explicit(addr, val, mem)
29 #define ATOMIC_LOAD(addr, mem) atomic_load_explicit(addr, mem)
30 #define ATOMIC_FETCH_ADD(addr, val, mem) atomic_fetch_add_explicit(addr, val, mem)
31 #define ATOMIC_FETCH_SUB(addr, val, mem) atomic_fetch_sub_explicit(addr, val, mem)
32 #define ATOMIC_CAS_WEAK(addr, old_val, new_val, mem1, mem2) \
33     atomic_compare_exchange_weak_explicit((addr), &(old_val), (new_val), (mem1), (mem2))
34 #define ASSERT(a) assert(a)
35 #define LIKELY(a) a
36 #define UNLIKELY(a) a
37 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
38 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
39 #else
40 #include <unistd.h>
41 #include <limits>
42 #include <sys/param.h>
43 #include <atomic>
44 #include <os/thread.h>
45 #include <sys/syscall.h>
46 #include <linux/futex.h>
47 namespace ark::os::unix::memory::futex {
48 #define THREAD_ID ark::os::thread::ThreadId                                // NOLINT(cppcoreguidelines-macro-usage)
49 #define GET_CURRENT_THREAD ark::os::thread::GetCurrentThreadId()           // NOLINT(cppcoreguidelines-macro-usage)
50 #define ATOMIC(type) std::atomic<type>                                     // NOLINT(cppcoreguidelines-macro-usage)
51 #define ATOMIC_INT ATOMIC(int)                                             // NOLINT(cppcoreguidelines-macro-usage)
52 #define ATOMIC_STORE(addr, val, mem) (addr)->store(val, std::mem)          // NOLINT(cppcoreguidelines-macro-usage)
53 #define ATOMIC_LOAD(addr, mem) (addr)->load(std::mem)                      // NOLINT(cppcoreguidelines-macro-usage)
54 #define ATOMIC_FETCH_ADD(addr, val, mem) (addr)->fetch_add(val, std::mem)  // NOLINT(cppcoreguidelines-macro-usage)
55 #define ATOMIC_FETCH_SUB(addr, val, mem) (addr)->fetch_sub(val, std::mem)  // NOLINT(cppcoreguidelines-macro-usage)
56 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
57 #define ATOMIC_CAS_WEAK(addr, old_val, new_val, mem1, mem2) \
58     (addr)->compare_exchange_weak(old_val, new_val, std::mem1, std::mem2)
59 #endif
60 
61 // Copy of mutex storage, after complete implementation should totally replace mutex::current_tid
62 // NOLINTNEXTLINE(readability-identifier-naming)
63 extern thread_local THREAD_ID current_tid;
64 
65 void MutexInit(struct fmutex *const m);
66 void MutexDestroy(struct fmutex *const m);
67 bool MutexLock(struct fmutex *const m, bool trylock);
68 bool MutexTryLockWithSpinning(struct fmutex *const m);
69 void MutexUnlock(struct fmutex *const m);
70 void MutexLockForOther(struct fmutex *const m, THREAD_ID thread);
71 void MutexUnlockForOther(struct fmutex *const m, THREAD_ID thread);
72 
73 #ifdef MC_ON
74 // GenMC does not support syscalls(futex)
75 // Models are defined in .c file to avoid code style warnings
76 #else
77 // NOLINTNEXTLINE(readability-identifier-naming)
futex(volatile int * uaddr,int op,int val,const struct timespec * timeout,volatile int * uaddr2,int val3)78 inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3)
79 {
80     // NOLINTNEXTLINE
81     return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
82 }
83 #endif
84 
85 static constexpr int WAKE_ONE = 1;
86 static constexpr int WAKE_ALL = INT_MAX;
87 static constexpr int32_t HELD_MASK = 1;
88 static constexpr int32_t WAITER_SHIFT = 1;
89 // NOLINTNEXTLINE(hicpp-signed-bitwise, cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
90 static constexpr int32_t WAITER_INCREMENT = 1 << WAITER_SHIFT;
91 
92 struct fmutex {
93     // Lowest bit: 0 - unlocked, 1 - locked.
94     // Other bits: Number of waiters.
95     // Unified lock state and waiters count to avoid requirement of double seq_cst memory order on mutex unlock
96     // as it's done in RWLock::WriteUnlock
97     ATOMIC_INT stateAndWaiters;
98     ATOMIC(THREAD_ID) exclusiveOwner;
99     int recursiveCount;
100     bool recursiveMutex;
101 };
102 
103 int *GetStateAddr(struct fmutex *const m);
104 void IncrementWaiters(struct fmutex *const m);
105 void DecrementWaiters(struct fmutex *const m);
106 int32_t GetWaiters(struct fmutex *const m);
107 bool IsHeld(struct fmutex *const m, THREAD_ID thread);
108 __attribute__((visibility("default"))) bool MutexDoNotCheckOnTerminationLoop();
109 __attribute__((visibility("default"))) void MutexIgnoreChecksOnTerminationLoop();
110 
111 struct CondVar {
112 #ifdef MC_ON
113     alignas(alignof(uint64_t)) struct fmutex *ATOMIC(mutexPtr);
114 #else
115     alignas(alignof(uint64_t)) ATOMIC(struct fmutex *) mutexPtr;
116 #endif
117     // The value itself is not important, detected only its change
118     ATOMIC(int32_t) cond;
119     ATOMIC(int32_t) waiters;
120 };
121 
122 __attribute__((visibility("default"))) void ConditionVariableInit(struct CondVar *const cond);
123 __attribute__((visibility("default"))) void ConditionVariableDestroy(struct CondVar *const cond);
124 __attribute__((visibility("default"))) void SignalCount(struct CondVar *const cond, int32_t toWake);
125 __attribute__((visibility("default"))) void Wait(struct CondVar *const cond, struct fmutex *const m);
126 __attribute__((visibility("default"))) bool TimedWait(struct CondVar *cond, struct fmutex *m, uint64_t ms, uint64_t ns,
127                                                       bool isAbsolute);
128 
129 #ifndef MC_ON
130 }  // namespace ark::os::unix::memory::futex
131 #endif
132 
133 #endif  // PANDA_LIBPANDABASE_PBASE_OS_UNIX_FUTEX_FMUTEX_H
134