C/C++ API Reference
Loading...
Searching...
No Matches
checker.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <atomic>
17#include <optional>
18
19#include "pw_sync/lock_annotations.h"
20#include "pw_thread/config.h"
21#include "pw_thread/thread.h"
22
23namespace pw {
24
26
57class PW_LOCKABLE("pw::ThreadChecker") ThreadChecker {
58 public:
59 explicit ThreadChecker(Thread::id id) : self_(id) {}
60
61 // Implementation of the BaseLockable requirement
62 void lock() PW_EXCLUSIVE_LOCK_FUNCTION() {
63#if PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
64 // Hitting this assert means that access to this checker from multiple
65 // threads was detected.
66 PW_ASSERT(pw::this_thread::get_id() == self_);
67#endif // PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
68 }
69 void unlock() PW_UNLOCK_FUNCTION() {}
70
71 private:
72 Thread::id self_;
73};
74
98class PW_LOCKABLE("pw::LazyInitThreadChecker") LazyInitThreadChecker {
99 public:
100 constexpr LazyInitThreadChecker()
101#if PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
102 : thread_id_()
103#endif
104 {
105 }
106
107 // Implementation of the BaseLockable requirement
108 void lock() PW_EXCLUSIVE_LOCK_FUNCTION() {
109#if PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
110 Thread::id stored_id = thread_id_.load(std::memory_order_acquire);
111 if (stored_id == Thread::id()) {
112 // The checker has not been initialized yet. Attempt to claim it for the
113 // current thread.
114 const Thread::id current_id = pw::this_thread::get_id();
115 // A default constructed id which is used as the expected value.
116 Thread::id uninitialized_id;
117 // Attempt to swap the uninitialized ID with the current thread's ID.
118 // This is done with release semantics to ensure that all prior writes
119 // on this thread are visible on other threads.
120 if (thread_id_.compare_exchange_strong(
121 uninitialized_id, current_id, std::memory_order_acq_rel)) {
122 // This thread successfully claimed the checker.
123 stored_id = current_id;
124 } else {
125 // Another thread claimed the checker. `uninitialized_id` is now updated
126 // with the stored value.
127 stored_id = uninitialized_id;
128 }
129 }
130
131 // Hitting this assert means that access to this checker from multiple
132 // threads was detected.
133 PW_ASSERT(pw::this_thread::get_id() == stored_id);
134#endif // PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
135 }
136 void unlock() PW_UNLOCK_FUNCTION() {}
137
138 private:
139#if PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
140 std::atomic<Thread::id> thread_id_;
141#endif // PW_THREAD_CHECKER_RUNTIME_ASSERT_ENABLED
142};
143
144} // namespace pw
Definition: checker.h:98
Definition: checker.h:57
#define PW_LOCKABLE(name)
Definition: lock_annotations.h:208
#define PW_EXCLUSIVE_LOCK_FUNCTION(...)
Definition: lock_annotations.h:230
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:247
::pw::thread::backend::NativeId id
Definition: thread.h:90
The Pigweed namespace.
Definition: alignment.h:27