Action Engine
Loading...
Searching...
No Matches
selectables.h
1// Copyright 2025 Google LLC
2//
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#ifndef THREAD_FIBER_SELECTABLES_H_
16#define THREAD_FIBER_SELECTABLES_H_
17
18#include <atomic>
19
20#include <absl/log/check.h>
21
22#include "thread/cases.h"
23
24namespace thread {
25// PermanentEvent
26// ---------------
27// Provides a level-triggered event which may be added to a Select statement.
28// PermanentEvents may only transition into a notified state. Selecting
29// against OnEvent() for an event that has already been signalled will always
30// return immediately.
31//
32// Memory ordering: For any threads X and Y, if X calls `Notify()`, then any
33// action taken by X before it calls `Notify()` is visible to thread Y after:
34// * Y selects OnEvent(), or
35// * Y receives a `true` return value from `HasBeenNotified()`
36class PermanentEvent final : public internal::Selectable {
37 public:
38 PermanentEvent() = default;
39
40 ~PermanentEvent() override {
41 // We acquire the lock here so that PermanentEvent can synchronize
42 // its own deletion.
43 splk_.lock();
44 DCHECK(cases_to_be_selected_ == nullptr);
45 }
46
47 PermanentEvent(const PermanentEvent&) = delete;
48 PermanentEvent& operator=(const PermanentEvent&) = delete;
49
50 // Signal that the event has occurred. Any Selectors on this event will be
51 // immediately notified, future Select statements against this event will be
52 // non-blocking. May only be called once.
53 void Notify();
54
55 // Returns true if Notify() has been called. False otherwise.
56 bool HasBeenNotified() const;
57
58 // May be passed to Select. Will always evaluate immediately for an event
59 // that has already been notified. Once the case has been signalled, then
60 // deleting the PermanentEvent will not interfere with the caller of Notify().
61 Case OnEvent() const {
62 Case c = {const_cast<PermanentEvent*>(this)};
63 return c;
64 }
65
66 // Implementation of Selectable interface.
67 bool Handle(internal::CaseInSelectClause* c, bool enqueue) override;
68 void Unregister(internal::CaseInSelectClause* c) override;
69
70 private:
71 friend class Fiber;
72
73 boost::fibers::detail::spinlock splk_;
74 std::atomic<bool> notified_{false};
75
76 internal::CaseInSelectClause* cases_to_be_selected_ = nullptr;
77};
78
79// NonSelectableCase()
80// -------------------
81// Provides a 'null' case which will never evaluate as ready by Select. This
82// may be used to substitute a Selectable that is no longer of interest within a
83// set, without re-labeling adjacent elements.
84//
85// Example:
86// int item;
87// bool ok;
88// thread::CaseArray cases = { chan1.reader()->OnRead(&item, &ok),
89// chan2.reader()->OnRead(&item, &ok) };
90//
91// while (1) {
92// int index = thread::Select(cases);
93// if (!ok) {
94// // Channel has been closed
95// cases[index] = NonSelectableCase();
96// } else {
97// ... process item
98// }
99Case NonSelectableCase();
100
101// AlwaysSelectableCase()
102// ----------------------
103// Provides case which will always evaluate as ready by Select. This may be
104// used when returning a Case for an event that is already known to be ready.
105//
106// Example:
107// class WorkItem {
108// public:
109// // Start the work and return a case that will become ready when
110// // the work has completed.
111// thread::Case Start() {
112// if (!status_.ok()) {
113// // An error has already been detected, so the work has completed.
114// return thread::AlwaysSelectableCase();
115// } else {
116// ... start real work ...
117// }
118// }
119// private:
120// util::Status status_;
121// };
122Case AlwaysSelectableCase();
123} // namespace thread
124
125#endif // THREAD_FIBER_SELECTABLES_H_
A Case represents a selectable case in a Select statement.
Definition cases.h:80