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