1 | //===-- condition_variable_linux.cpp ----------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "platform.h" |
10 | |
11 | #if SCUDO_LINUX |
12 | |
13 | #include "condition_variable_linux.h" |
14 | |
15 | #include "atomic_helpers.h" |
16 | |
17 | #include <limits.h> |
18 | #include <linux/futex.h> |
19 | #include <sys/syscall.h> |
20 | #include <unistd.h> |
21 | |
22 | namespace scudo { |
23 | |
24 | void ConditionVariableLinux::notifyAllImpl(UNUSED HybridMutex &M) { |
25 | const u32 V = atomic_load_relaxed(A: &Counter); |
26 | atomic_store_relaxed(A: &Counter, V: V + 1); |
27 | |
28 | // TODO(chiahungduan): Move the waiters from the futex waiting queue |
29 | // `Counter` to futex waiting queue `M` so that the awoken threads won't be |
30 | // blocked again due to locked `M` by current thread. |
31 | if (LastNotifyAll != V) { |
32 | syscall(SYS_futex, reinterpret_cast<uptr>(&Counter), FUTEX_WAKE_PRIVATE, |
33 | INT_MAX, nullptr, nullptr, 0); |
34 | } |
35 | |
36 | LastNotifyAll = V + 1; |
37 | } |
38 | |
39 | void ConditionVariableLinux::waitImpl(HybridMutex &M) { |
40 | const u32 V = atomic_load_relaxed(A: &Counter) + 1; |
41 | atomic_store_relaxed(A: &Counter, V); |
42 | |
43 | // TODO: Use ScopedUnlock when it's supported. |
44 | M.unlock(); |
45 | syscall(SYS_futex, reinterpret_cast<uptr>(&Counter), FUTEX_WAIT_PRIVATE, V, |
46 | nullptr, nullptr, 0); |
47 | M.lock(); |
48 | } |
49 | |
50 | } // namespace scudo |
51 | |
52 | #endif // SCUDO_LINUX |
53 | |