/src/gpowerd/callback_manager.cc
Line | Count | Source |
1 | | #include "callback_manager.h" |
2 | | |
3 | | #include <memory> |
4 | | #include <utility> |
5 | | #include <vector> |
6 | | |
7 | | #include "absl/functional/any_invocable.h" |
8 | | #include "absl/synchronization/mutex.h" |
9 | | |
10 | | namespace safepower_agent { |
11 | | |
12 | | CallbackManager::Handle::Handle(std::shared_ptr<HandleImpl> impl) |
13 | 0 | : impl_(std::move(impl)) {} |
14 | | |
15 | 0 | bool CallbackManager::Handle::pending() const { |
16 | 0 | if (impl_ == nullptr) return false; |
17 | 0 | absl::MutexLock lock(&impl_->mutex); |
18 | 0 | return impl_->state == State::kPending || impl_->state == State::kExecuting; |
19 | 0 | } |
20 | | |
21 | 0 | bool CallbackManager::Handle::executed() const { |
22 | 0 | if (impl_ == nullptr) return false; |
23 | 0 | absl::MutexLock lock(&impl_->mutex); |
24 | 0 | return impl_->state == State::kExecuted; |
25 | 0 | } |
26 | | |
27 | 0 | bool CallbackManager::Handle::TryCancel() { |
28 | 0 | if (impl_ == nullptr) return false; |
29 | 0 | absl::MutexLock lock(&impl_->mutex); |
30 | 0 | if (impl_->state == State::kPending) { |
31 | 0 | impl_->callback = nullptr; |
32 | 0 | impl_->state = State::kCancelled; |
33 | 0 | return true; |
34 | 0 | } |
35 | 0 | return false; |
36 | 0 | } |
37 | | |
38 | 0 | void CallbackManager::Handle::Wait() { |
39 | 0 | if (impl_ == nullptr) return; |
40 | 0 | absl::MutexLock lock(&impl_->mutex); |
41 | 0 | impl_->mutex.Await(absl::Condition( |
42 | 0 | +[](State* state) { |
43 | 0 | return *state == State::kCancelled || *state == State::kExecuted; |
44 | 0 | }, |
45 | 0 | &impl_->state)); |
46 | 0 | } |
47 | | |
48 | | |
49 | 0 | CallbackManager::Handle CallbackManager::RunFirst(Callback callback) { |
50 | 0 | auto impl = std::make_shared<HandleImpl>(); |
51 | 0 | impl->callback = std::move(callback); |
52 | 0 | { |
53 | 0 | absl::MutexLock lock(&mutex_); |
54 | 0 | run_first_.push_back(impl); |
55 | 0 | } |
56 | 0 | return Handle(std::move(impl)); |
57 | 0 | } |
58 | | |
59 | 0 | CallbackManager::Handle CallbackManager::RunLast(Callback callback) { |
60 | 0 | auto impl = std::make_shared<HandleImpl>(); |
61 | 0 | impl->callback = std::move(callback); |
62 | 0 | { |
63 | 0 | absl::MutexLock lock(&mutex_); |
64 | 0 | run_last_.push_back(impl); |
65 | 0 | } |
66 | 0 | return Handle(std::move(impl)); |
67 | 0 | } |
68 | | |
69 | | void CallbackManager::RunCallbackIfValid( |
70 | 0 | const std::weak_ptr<HandleImpl>& weak_handle) { |
71 | 0 | Callback cb; |
72 | 0 | std::shared_ptr<HandleImpl> handle = weak_handle.lock(); |
73 | 0 | if (handle) { |
74 | 0 | { |
75 | 0 | absl::MutexLock lock(&handle->mutex); |
76 | 0 | if (handle->state == State::kPending) { |
77 | 0 | cb = std::exchange(handle->callback, nullptr); |
78 | 0 | if (!cb) { |
79 | | // If the callback was registered as empty/nullptr, transition |
80 | | // directly to kExecuted so that we don't get stuck in kExecuting. |
81 | 0 | handle->state = State::kExecuted; |
82 | 0 | return; |
83 | 0 | } |
84 | 0 | handle->state = State::kExecuting; |
85 | 0 | } |
86 | 0 | } |
87 | 0 | } |
88 | 0 | if (cb) { |
89 | 0 | std::move(cb)(); |
90 | 0 | absl::MutexLock lock(&handle->mutex); |
91 | 0 | handle->state = State::kExecuted; |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | 0 | void CallbackManager::RunCallbacks() { |
96 | 0 | std::vector<std::weak_ptr<HandleImpl>> first_snapshot; |
97 | 0 | std::vector<std::weak_ptr<HandleImpl>> last_snapshot; |
98 | 0 | { |
99 | 0 | absl::MutexLock lock(&mutex_); |
100 | 0 | first_snapshot = std::move(run_first_); |
101 | 0 | last_snapshot = std::move(run_last_); |
102 | 0 | run_first_.clear(); |
103 | 0 | run_last_.clear(); |
104 | 0 | } |
105 | | |
106 | | // Run first callbacks in reverse (LIFO) order |
107 | 0 | for (auto it = first_snapshot.rbegin(); it != first_snapshot.rend(); ++it) { |
108 | 0 | RunCallbackIfValid(*it); |
109 | 0 | } |
110 | | |
111 | | // Run last callbacks in forward (FIFO) order |
112 | 0 | for (auto it = last_snapshot.begin(); it != last_snapshot.end(); ++it) { |
113 | 0 | RunCallbackIfValid(*it); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | } // namespace safepower_agent |