• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 PLATFORMS_UNIX_LIBPANDABASE_FUTEX_FMUTEX_H
17 #define PLATFORMS_UNIX_LIBPANDABASE_FUTEX_FMUTEX_H
18 
19 #include <unistd.h>
20 
21 #ifdef MC_ON
22 #include <cassert>
23 #include <climits>
24 #include <pthread.h>
25 #include <stdatomic.h>
26 #define THREAD_ID pthread_t
27 #define GET_CURRENT_THREAD pthread_self()
28 #define ATOMIC(type) _Atomic type
29 #define ATOMIC_INT atomic_int
30 #define ATOMIC_STORE(addr, val, mem) atomic_store_explicit(addr, val, mem)
31 #define ATOMIC_LOAD(addr, mem) atomic_load_explicit(addr, mem)
32 #define ATOMIC_FETCH_ADD(addr, val, mem) atomic_fetch_add_explicit(addr, val, mem)
33 #define ATOMIC_FETCH_SUB(addr, val, mem) atomic_fetch_sub_explicit(addr, val, mem)
34 #define ATOMIC_CAS_WEAK(addr, old_val, new_val, mem1, mem2) \
35     atomic_compare_exchange_weak_explicit(addr, &old_val, new_val, mem1, mem2)
36 #define ASSERT(a) assert(a)
37 #define LIKELY(a) a
38 #define UNLIKELY(a) a
39 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
40 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
41 #else
42 #include <limits>
43 #include <sys/param.h>
44 #include <atomic>
45 #include <os/thread.h>
46 #include <linux/futex.h>
47 #include <sys/syscall.h>
48 namespace panda::os::unix::memory::futex {
49 #define THREAD_ID thread::ThreadId                                         // NOLINT(cppcoreguidelines-macro-usage)
50 #define GET_CURRENT_THREAD os::thread::GetCurrentThreadId()                // NOLINT(cppcoreguidelines-macro-usage)
51 #define ATOMIC(type) std::atomic<type>                                     // NOLINT(cppcoreguidelines-macro-usage)
52 #define ATOMIC_INT ATOMIC(int)                                             // NOLINT(cppcoreguidelines-macro-usage)
53 #define ATOMIC_STORE(addr, val, mem) (addr)->store(val, std::mem)          // NOLINT(cppcoreguidelines-macro-usage)
54 #define ATOMIC_LOAD(addr, mem) (addr)->load(std::mem)                      // NOLINT(cppcoreguidelines-macro-usage)
55 #define ATOMIC_FETCH_ADD(addr, val, mem) (addr)->fetch_add(val, std::mem)  // NOLINT(cppcoreguidelines-macro-usage)
56 #define ATOMIC_FETCH_SUB(addr, val, mem) (addr)->fetch_sub(val, std::mem)  // NOLINT(cppcoreguidelines-macro-usage)
57 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
58 #define ATOMIC_CAS_WEAK(addr, old_val, new_val, mem1, mem2) \
59     (addr)->compare_exchange_weak(old_val, new_val, std::mem1, std::mem2)
60 #endif
61 
62 // Copy of mutex storage, after complete implementation should totally replace mutex::current_tid
63 extern thread_local THREAD_ID current_tid;
64 
65 void MutexInit(struct fmutex *m);
66 void MutexDestroy(struct fmutex *m);
67 bool MutexLock(struct fmutex *m, bool trylock);
68 bool MutexTryLockWithSpinning(struct fmutex *m);
69 void MutexUnlock(struct fmutex *m);
70 void MutexLockForOther(struct fmutex *m, THREAD_ID thread);
71 void MutexUnlockForOther(struct fmutex *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
futex(volatile int * uaddr,int op,int val,const struct timespec * timeout,volatile int * uaddr2,int val3)77 inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout, volatile int *uaddr2, int val3)
78 {
79     // NOLINTNEXTLINE
80     return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
81 }
82 #endif
83 
84 static constexpr int WAKE_ONE = 1;
85 static constexpr int WAKE_ALL = INT_MAX;
86 static constexpr int32_t HELD_MASK = 1;
87 static constexpr int32_t WAITER_SHIFT = 1;
88 // NOLINTNEXTLINE(hicpp-signed-bitwise, cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
89 static constexpr int32_t WAITER_INCREMENT = 1 << WAITER_SHIFT;
90 
91 struct fmutex {
92     // Lowest bit: 0 - unlocked, 1 - locked.
93     // Other bits: Number of waiters.
94     // Unified lock state and waiters count to avoid requirement of double seq_cst memory order on mutex unlock
95     // as it's done in RWLock::WriteUnlock
96     ATOMIC_INT state_and_waiters_;
97     ATOMIC(THREAD_ID) exclusive_owner_;
98     int recursiveCount;
99     bool recursive_mutex_;
100 };
101 
102 int *GetStateAddr(struct fmutex *const m);
103 void IncrementWaiters(struct fmutex *m);
104 void DecrementWaiters(struct fmutex *m);
105 int32_t GetWaiters(struct fmutex *const m);
106 bool IsHeld(struct fmutex *const m, THREAD_ID thread);
107 bool MutexDoNotCheckOnDeadlock();
108 void MutexIgnoreChecksOnDeadlock();
109 
110 #ifdef MC_ON
111 #else
112 }  // namespace panda::os::unix::memory::futex
113 #endif
114 
115 #endif  // PLATFORMS_UNIX_LIBPANDABASE_FUTEX_FMUTEX_H
116