Realm
A distributed, event-based tasking library
Loading...
Searching...
No Matches
event_impl.h
Go to the documentation of this file.
1/*
2 * Copyright 2025 Stanford University, NVIDIA Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18// Event/UserEvent implementations for Realm
19
20#ifndef REALM_EVENT_IMPL_H
21#define REALM_EVENT_IMPL_H
22
23#include "realm/event.h"
24#include "realm/id.h"
25#include "realm/nodeset.h"
26#include "realm/faults.h"
27
28#include "realm/network.h"
29#include <realm/activemsg.h>
30
31#include "realm/lists.h"
32#include "realm/threads.h"
33#include "realm/logging.h"
34#include "realm/redop.h"
35#include "realm/bgwork.h"
36#include "realm/dynamic_table.h"
37
38#include <vector>
39#include <map>
40#include <memory>
41
42namespace Realm {
43
44 class GenEventImpl;
45
46 extern Logger log_poison; // defined in event_impl.cc
47 class ProcessorImpl; // defined in proc_impl.h
48
50 public:
51 virtual ~EventWaiter(void) {}
52 virtual void event_triggered(bool poisoned, TimeLimit work_until) = 0;
53 virtual void print(std::ostream &os) const = 0;
54 virtual Event get_finish_event(void) const = 0;
55
61 };
62
63 // triggering events can often result in recursive expansion of work -
64 // this widget flattens the call stack and defers excessive triggers
65 // to avoid stalling the initial triggerer longer than they want
83
84 // parent class of GenEventImpl and BarrierImpl
85 class EventImpl {
86 public:
87 typedef unsigned gen_t;
88
89 EventImpl(void);
90 virtual ~EventImpl(void);
91
92 // test whether an event has triggered without waiting
93 virtual bool has_triggered(gen_t needed_gen, bool &poisoned) = 0;
94
95 virtual void subscribe(gen_t subscribe_gen) = 0;
96
97 // causes calling thread to block until event has occurred
98 // void wait(Event::gen_t needed_gen);
99
100 virtual void external_wait(gen_t needed_gen, bool &poisoned) = 0;
101 virtual bool external_timedwait(gen_t needed_gen, bool &poisoned,
102 long long max_ns) = 0;
103
104 // helper to create the Event for an arbitrary generation
106
107 virtual bool add_waiter(gen_t needed_gen,
108 EventWaiter *waiter /*, bool pre_subscribed = false*/) = 0;
109
110 static bool add_waiter(Event needed, EventWaiter *waiter);
111
112 // use this sparingly - it has to hunt through waiter lists while
113 // holding locks
114 virtual bool remove_waiter(gen_t needed_gen, EventWaiter *waiter) = 0;
115
116 static bool detect_event_chain(Event search_from, Event target, int max_depth,
117 bool print_chain);
118
119 public:
123 };
124
125 class GenEventImpl;
126
128 public:
131
132 bool is_active(void) const;
133
134 void prepare_merger(Event _finish_event, bool _ignore_faults,
135 std::optional<size_t> expected_events = std::optional<size_t>());
136
137 void add_precondition(Event wait_for);
138
139 void arm_merger(void);
140
142 public:
143 MergeEventPrecondition(void) = default;
146 virtual ~MergeEventPrecondition(void) = default;
147
148 public:
150
151 virtual void event_triggered(bool poisoned, TimeLimit work_until);
152 virtual void print(std::ostream &os) const;
153 virtual Event get_finish_event(void) const;
154 };
155
156 // as an alternative to add_precondition, get_next_precondition can
157 // be used to get a precondition that can manually be added to a waiter
158 // list
160
161 protected:
162 void precondition_triggered(bool poisoned, TimeLimit work_until,
163 MergeEventPrecondition *precondition = nullptr);
164
166
174
175 static constexpr size_t MAX_INLINE_PRECONDITIONS = 6;
177 // std::deque does not invalidate references on resize
178 std::deque<MergeEventPrecondition> overflow_preconditions;
180 };
181
183 public:
184 virtual ~EventCommunicator() = default;
185
186 virtual void trigger(Event event, NodeID owner, bool poisoned);
187
188 virtual void update(Event event, NodeSet to_update,
189 span<EventImpl::gen_t> poisoned_generations);
190
191 virtual void update(Event event, NodeID to_update,
192 span<EventImpl::gen_t> poisoned_generations);
193
194 virtual void subscribe(Event event, NodeID owner,
195 EventImpl::gen_t previous_subscribe_gen);
196 };
197
198 class GenEventImpl : public EventImpl {
199 public:
201
203 GenEventImpl(EventTriggerNotifier *_event_triggerer, EventCommunicator *_event_comm);
205
206 void init(ID _me, unsigned _init_owner);
207
208 static GenEventImpl *
209 create_genevent(void); // TODO: remove this once we get rid of get_runtime()
210
212
213 static ID make_id(const GenEventImpl &dummy, int owner, ID::IDType index)
214 {
215 return ID::make_event(owner, index, 0);
216 }
217
218 // get the Event (id+generation) for the current (i.e. untriggered) generation
219 Event current_event(void) const;
220
221 // test whether an event has triggered without waiting
222 virtual bool has_triggered(gen_t needed_gen, bool &poisoned);
223
224 virtual void subscribe(gen_t subscribe_gen);
225 void handle_remote_subscription(NodeID sender, gen_t subscribe_gen,
226 gen_t previous_subscribe_gen);
227
228 virtual void external_wait(gen_t needed_gen, bool &poisoned);
229 virtual bool external_timedwait(gen_t needed_gen, bool &poisoned, long long max_ns);
230
231 virtual bool add_waiter(gen_t needed_gen, EventWaiter *waiter);
232
233 // use this sparingly - it has to hunt through waiter lists while
234 // holding locks
235 virtual bool remove_waiter(gen_t needed_gen, EventWaiter *waiter);
236
237 // creates an event that won't trigger until all input events have
238 static Event merge_events(span<const Event> wait_for, bool ignore_faults);
241 Event ev6 = Event::NO_EVENT);
242 static Event ignorefaults(Event wait_for);
243
244 // record that the event has triggered and notify anybody who cares
245 bool trigger(gen_t gen_triggered, int trigger_node, bool poisoned,
246 TimeLimit work_until);
247
248 // helper for triggering with an Event (which must be backed by a GenEventImpl)
249 static void trigger(Event e, bool poisoned);
250 static void trigger(Event e, bool poisoned, TimeLimit work_until);
251
252 // process an update message from the owner
253 void process_update(gen_t current_gen, const gen_t *new_poisoned_generations,
254 int new_poisoned_count, TimeLimit work_until);
255
256 // Set the operation that will trigger this event's generation.
258 // Get the operation that will trigger this event's generation.
259 // The returned operation's reference is incremented and must be removed by the
260 // caller.
262
265
266 GenEventImplAllocator(void) = default;
267
271
272 void construct(GenEventImpl *storage, ID id, unsigned owner) const
273 {
274 storage->~GenEventImpl();
275 new(storage) GenEventImpl(triggerer, new EventCommunicator());
276 storage->init(id, owner);
277 }
278 };
279
280 public: // protected:
281 // these state variables are monotonic, so can be checked without a lock for
282 // early-out conditions
286 bool has_local_triggers = false;
287
288 bool is_generation_poisoned(gen_t gen) const; // helper function - linear search
289
290 // this is only manipulated when the event is "idle"
292
293 // used for merge_events and delayed UserEvent triggers
295
297 std::unique_ptr<EventCommunicator> event_comm{nullptr};
298
299 // everything below here protected by this mutex
301
302 // The operation that will trigger this generation
304
305 // local waiters are tracked by generation - an easily-accessed list is used
306 // for the "current" generation, whereas a map-by-generation-id is used for
307 // "future" generations (i.e. ones ahead of what we've heard about if we're
308 // not the owner)
310 std::map<gen_t, EventWaiter::EventWaiterList> future_local_waiters;
311
312 // external waiters on this node are notifies via a condition variable
314 // use kernel mutex for timedwait functionality
317
318 // remote waiters are kept in a bitmask for the current generation - this is
319 // only maintained on the owner, who never has to worry about more than one
320 // generation
322
323 // we'll set an upper bound on how many times any given event can be poisoned - this
324 // keeps update messages from growing without bound
325 static const int POISONED_GENERATION_LIMIT = 16;
326
327 // note - we don't bother sorting the list below - the overhead of a binary search
328 // dominates for short lists
329 // we also can't use an STL vector because reallocation prevents us from reading the
330 // list without the lock - instead we'll allocate the max size if/when we need
331 // any space
333
334 // local triggerings - if we're not the owner, but we've triggered/poisoned events,
335 // we need to give consistent answers for those generations, so remember what we've
336 // done until our view of the distributed event catches up
337 // value stored in map is whether generation was poisoned
338 std::map<gen_t, bool> local_triggers;
339
340 // these resolve a race condition between the early trigger of a
341 // poisoned merge and the last precondition
343 friend class EventMerger;
344 };
345}; // namespace Realm
346
347#include "realm/event_impl.inl"
348
349#endif // ifndef REALM_EVENT_IMPL_H
Definition bgwork.h:129
Definition threads.h:428
Definition event_impl.h:182
virtual void trigger(Event event, NodeID owner, bool poisoned)
virtual void update(Event event, NodeID to_update, span< EventImpl::gen_t > poisoned_generations)
virtual void subscribe(Event event, NodeID owner, EventImpl::gen_t previous_subscribe_gen)
virtual ~EventCommunicator()=default
virtual void update(Event event, NodeSet to_update, span< EventImpl::gen_t > poisoned_generations)
Definition event_impl.h:85
virtual bool remove_waiter(gen_t needed_gen, EventWaiter *waiter)=0
NodeID owner
Definition event_impl.h:122
virtual bool has_triggered(gen_t needed_gen, bool &poisoned)=0
Event make_event(gen_t gen) const
virtual void external_wait(gen_t needed_gen, bool &poisoned)=0
virtual bool external_timedwait(gen_t needed_gen, bool &poisoned, long long max_ns)=0
unsigned gen_t
Definition event_impl.h:87
virtual void subscribe(gen_t subscribe_gen)=0
static bool detect_event_chain(Event search_from, Event target, int max_depth, bool print_chain)
ProcessorImpl * owning_processor
Definition event_impl.h:121
static bool add_waiter(Event needed, EventWaiter *waiter)
ID me
Definition event_impl.h:120
virtual bool add_waiter(gen_t needed_gen, EventWaiter *waiter)=0
virtual ~EventImpl(void)
virtual void event_triggered(bool poisoned, TimeLimit work_until)
EventMerger * merger
Definition event_impl.h:149
MergeEventPrecondition(const MergeEventPrecondition &)=delete
MergeEventPrecondition(MergeEventPrecondition &&)=delete
virtual ~MergeEventPrecondition(void)=default
virtual Event get_finish_event(void) const
virtual void print(std::ostream &os) const
Definition event_impl.h:127
std::deque< MergeEventPrecondition > overflow_preconditions
Definition event_impl.h:178
static constexpr size_t MAX_INLINE_PRECONDITIONS
Definition event_impl.h:175
GenEventImpl * event_impl
Definition event_impl.h:167
bool ignore_faults
Definition event_impl.h:170
void arm_merger(void)
atomic< int > faults_observed
Definition event_impl.h:173
MergeEventPrecondition * get_next_precondition(void)
EventImpl::gen_t finish_gen
Definition event_impl.h:168
bool recycle_preconditions
Definition event_impl.h:171
void add_precondition(Event wait_for)
void prepare_merger(Event _finish_event, bool _ignore_faults, std::optional< size_t > expected_events=std::optional< size_t >())
unsigned precondition_offset
Definition event_impl.h:169
EventMerger(GenEventImpl *_event_impl)
EventWaiter::EventWaiterList free_preconditions
Definition event_impl.h:179
atomic< int > count_needed
Definition event_impl.h:172
MergeEventPrecondition inline_preconditions[MAX_INLINE_PRECONDITIONS]
Definition event_impl.h:176
void precondition_triggered(bool poisoned, TimeLimit work_until, MergeEventPrecondition *precondition=nullptr)
bool is_active(void) const
Definition event_impl.h:66
Mutex mutex
Definition event_impl.h:76
virtual bool do_work(TimeLimit work_until)
static thread_local EventWaiter::EventWaiterList * nested_poisoned
Definition event_impl.h:81
static thread_local EventWaiter::EventWaiterList * nested_normal
Definition event_impl.h:80
EventWaiter::EventWaiterList delayed_poisoned
Definition event_impl.h:78
void trigger_event_waiters(EventWaiter::EventWaiterList &to_trigger, bool poisoned, TimeLimit trigger_until)
EventWaiter::EventWaiterList delayed_normal
Definition event_impl.h:77
Definition event_impl.h:49
virtual ~EventWaiter(void)
Definition event_impl.h:51
REALM_PMTA_DEFN(EventWaiter, IntrusiveListLink< EventWaiter >, ew_list_link)
IntrusiveListLink< EventWaiter > ew_list_link
Definition event_impl.h:56
virtual Event get_finish_event(void) const =0
IntrusiveList< EventWaiter, REALM_PMTA_USE(EventWaiter, ew_list_link), DummyLock > EventWaiterList
Definition event_impl.h:60
virtual void event_triggered(bool poisoned, TimeLimit work_until)=0
virtual void print(std::ostream &os) const =0
Definition event.h:50
static const Event NO_EVENT
The value should be usued to initialize an event handle. NO_EVENT is always in has triggered state .
Definition event.h:71
Definition event_impl.h:198
Operation * current_trigger_op
Definition event_impl.h:303
bool is_generation_poisoned(gen_t gen) const
std::map< gen_t, bool > local_triggers
Definition event_impl.h:338
static void trigger(Event e, bool poisoned, TimeLimit work_until)
atomic< gen_t > gen_subscribed
Definition event_impl.h:284
static Event merge_events(span< const Event > wait_for, bool ignore_faults)
virtual bool add_waiter(gen_t needed_gen, EventWaiter *waiter)
void init(ID _me, unsigned _init_owner)
gen_t * poisoned_generations
Definition event_impl.h:332
NodeSet remote_waiters
Definition event_impl.h:321
static Event ignorefaults(Event wait_for)
static const ID::ID_Types ID_TYPE
Definition event_impl.h:200
KernelMutex external_waiter_mutex
Definition event_impl.h:315
std::unique_ptr< EventCommunicator > event_comm
Definition event_impl.h:297
Operation * get_trigger_op(gen_t gen)
bool trigger(gen_t gen_triggered, int trigger_node, bool poisoned, TimeLimit work_until)
void handle_remote_subscription(NodeID sender, gen_t subscribe_gen, gen_t previous_subscribe_gen)
KernelMutex::CondVar external_waiter_condvar
Definition event_impl.h:316
bool free_list_insertion_delayed
Definition event_impl.h:342
virtual bool remove_waiter(gen_t needed_gen, EventWaiter *waiter)
GenEventImpl(EventTriggerNotifier *_event_triggerer, EventCommunicator *_event_comm)
static void trigger(Event e, bool poisoned)
static Event merge_events(Event ev1, Event ev2, Event ev3=Event::NO_EVENT, Event ev4=Event::NO_EVENT, Event ev5=Event::NO_EVENT, Event ev6=Event::NO_EVENT)
virtual void subscribe(gen_t subscribe_gen)
EventTriggerNotifier * event_triggerer
Definition event_impl.h:296
EventWaiter::EventWaiterList current_local_waiters
Definition event_impl.h:309
bool has_external_waiters
Definition event_impl.h:313
Event current_event(void) const
static GenEventImpl * create_genevent(void)
EventMerger merger
Definition event_impl.h:294
virtual bool has_triggered(gen_t needed_gen, bool &poisoned)
atomic< int > num_poisoned_generations
Definition event_impl.h:285
static const int POISONED_GENERATION_LIMIT
Definition event_impl.h:325
bool has_local_triggers
Definition event_impl.h:286
static ID make_id(const GenEventImpl &dummy, int owner, ID::IDType index)
Definition event_impl.h:213
std::map< gen_t, EventWaiter::EventWaiterList > future_local_waiters
Definition event_impl.h:310
virtual bool external_timedwait(gen_t needed_gen, bool &poisoned, long long max_ns)
void process_update(gen_t current_gen, const gen_t *new_poisoned_generations, int new_poisoned_count, TimeLimit work_until)
Mutex mutex
Definition event_impl.h:300
virtual void external_wait(gen_t needed_gen, bool &poisoned)
void set_trigger_op(gen_t gen, Operation *op)
GenEventImpl * next_free
Definition event_impl.h:291
atomic< gen_t > generation
Definition event_impl.h:283
static GenEventImpl * create_genevent(RuntimeImpl *runtime_impl)
Definition id.h:30
static ID make_event(unsigned creator_node, unsigned gen_event_idx, unsigned generation)
ID_Types
Definition id.h:250
@ ID_EVENT
Definition id.h:253
::realm_id_t IDType
Definition id.h:32
Definition lists.h:66
Definition mutex.h:359
Definition mutex.h:273
Definition nodeset.h:117
Definition operation.h:32
Definition proc_impl.h:51
Definition runtime_impl.h:264
Definition timers.h:129
Definition mutex.h:223
Definition atomics.h:31
Definition utils.h:84
#define REALM_PMTA_USE(structtype, name)
Definition lists.h:42
Definition activemsg.h:38
Logger log_poison
int NodeID
Definition nodeset.h:40
GenEventImplAllocator(EventTriggerNotifier *t)
Definition event_impl.h:268
void construct(GenEventImpl *storage, ID id, unsigned owner) const
Definition event_impl.h:272
EventTriggerNotifier * triggerer
Definition event_impl.h:264