Tamer
C++ language extensions for event-driven programming
Loading...
Searching...
No Matches
rendezvous.hh
Go to the documentation of this file.
1#ifndef TAMER_RENDEZVOUS_HH
2#define TAMER_RENDEZVOUS_HH 1
3/* Copyright (c) 2007-2015, Eddie Kohler
4 * Copyright (c) 2007, Regents of the University of California
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, subject to the conditions
9 * listed in the Tamer LICENSE file. These conditions include: you must
10 * preserve this copyright notice, and you cannot mention the copyright
11 * holders in advertising related to the Software without their permission.
12 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
13 * notice is a summary of the Tamer LICENSE file; the license in that file is
14 * legally binding.
15 */
16#include <cassert>
17#include <cstring>
18#include <tamer/xbase.hh>
19namespace tamer {
20
24
35template <typename I>
36class rendezvous : public tamerpriv::explicit_rendezvous,
37 public one_argument_rendezvous_tag<rendezvous<I> > {
38 public:
39 inline ~rendezvous();
40
41 template <typename T0, typename T1, typename T2, typename T3>
42 inline event<T0, T1, T2, T3> make_event(const I& eid,
43 T0& x0, T1& x1, T2& x2, T3& x3);
44 template <typename T0, typename T1, typename T2>
45 inline event<T0, T1, T2> make_event(const I& eid, T0& x0, T1& x1, T2& x2);
46 template <typename T0, typename T1>
47 inline event<T0, T1> make_event(const I& eid, T0& x0, T1& x1);
48 template <typename T0>
49 inline event<T0> make_event(const I& eid, T0& x0);
50 inline event<> make_event(const I& eid);
51
52 inline bool has_ready() const;
53 inline bool has_waiting() const;
54 inline bool has_events() const;
55
56 inline bool join(I& eid);
57 void clear();
58
59 inline uintptr_t make_rid(const I& eid);
60 using tamerpriv::blocking_rendezvous::block;
61};
62
63
65template <typename I>
67 if (waiting_ || ready_) {
68 clear();
69 }
70}
71
76template <typename I>
77inline bool rendezvous<I>::has_ready() const {
78 return ready_;
79}
80
84template <typename I>
85inline bool rendezvous<I>::has_waiting() const {
86 return waiting_;
87}
88
90template <typename I>
91inline bool rendezvous<I>::has_events() const {
92 return ready_ || waiting_;
93}
94
101template <typename I>
102inline bool rendezvous<I>::join(I& eid) {
103 if (ready_) {
104 I* eidp = reinterpret_cast<I*>(pop_ready());
105 eid = std::move(*eidp);
106 delete eidp;
107 return true;
108 } else {
109 return false;
110 }
111}
112
117template <typename I>
119 for (tamerpriv::simple_event* e = waiting_; e; e = e->next()) {
120 delete reinterpret_cast<I*>(e->rid());
121 }
122 abstract_rendezvous::remove_waiting();
123 for (tamerpriv::simple_event* e = ready_; e; e = e->next()) {
124 delete reinterpret_cast<I*>(e->rid());
125 }
126 explicit_rendezvous::remove_ready();
127}
128
133template <typename I>
134inline uintptr_t rendezvous<I>::make_rid(const I& eid) {
135 return reinterpret_cast<uintptr_t>(new I(eid));
136}
137
138
140
141template <typename I>
142class simple_rendezvous : public tamerpriv::explicit_rendezvous,
143 public one_argument_rendezvous_tag<simple_rendezvous<I> > {
144 public:
145 inline ~simple_rendezvous();
146
147 template <typename T0, typename T1, typename T2, typename T3>
148 inline event<T0, T1, T2, T3> make_event(I eid,
149 T0& x0, T1& x1, T2& x2, T3& x3);
150 template <typename T0, typename T1, typename T2>
151 inline event<T0, T1, T2> make_event(I eid, T0& x0, T1& x1, T2& x2);
152 template <typename T0, typename T1>
153 inline event<T0, T1> make_event(I eid, T0& x0, T1& x1);
154 template <typename T0>
155 inline event<T0> make_event(I eid, T0& x0);
156 inline event<> make_event(I eid);
157
158 inline bool has_ready() const { return ready_; }
159 inline bool has_waiting() const { return waiting_; }
160 inline bool has_events() const { return ready_ || waiting_; }
161
162 inline bool join(I& eid);
163 void clear();
164
165 inline uintptr_t make_rid(I eid) TAMER_NOEXCEPT;
166 using tamerpriv::blocking_rendezvous::block;
167};
168
169template <typename T>
170inline simple_rendezvous<T>::~simple_rendezvous() {
171 if (waiting_ || ready_) {
172 clear();
173 }
174}
175
176template <typename T>
177inline bool simple_rendezvous<T>::join(T& eid) {
178 if (ready_) {
179 eid = tamerpriv::rid_cast<T>::out(pop_ready());
180 return true;
181 } else {
182 return false;
183 }
184}
185
186template <typename T>
187void simple_rendezvous<T>::clear() {
188 abstract_rendezvous::remove_waiting();
189 explicit_rendezvous::remove_ready();
190}
191
192template <typename T>
193inline uintptr_t simple_rendezvous<T>::make_rid(T eid) TAMER_NOEXCEPT {
194 return tamerpriv::rid_cast<T>::in(eid);
195}
196
197
198template <>
199class rendezvous<uintptr_t> : public simple_rendezvous<uintptr_t> {
200};
201
202template <typename T>
203class rendezvous<T*> : public simple_rendezvous<T*> {
204};
205
206template <>
207class rendezvous<int> : public simple_rendezvous<int> {
208};
209
210template <>
211class rendezvous<bool> : public simple_rendezvous<bool> {
212};
213
214
215template <>
216class rendezvous<> : public tamerpriv::explicit_rendezvous,
217 public zero_argument_rendezvous_tag<rendezvous<> > {
218 public:
219 inline ~rendezvous() {
220 if (waiting_ || ready_) {
221 clear();
222 }
223 }
224
225 template <typename T0, typename T1, typename T2, typename T3>
226 inline event<T0, T1, T2, T3> make_event(T0& x0, T1& x1, T2& x2, T3& x3);
227 template <typename T0, typename T1, typename T2>
228 inline event<T0, T1, T2> make_event(T0& x0, T1& x1, T2& x2);
229 template <typename T0, typename T1>
230 inline event<T0, T1> make_event(T0& x0, T1& x1);
231#if !TAMER_HAVE_PREEVENT || !TAMER_PREFER_PREEVENT
232 template <typename T0>
233 inline event<T0> make_event(T0& x0);
234 inline event<> make_event();
235#else
236 template <typename T0>
237 inline preevent<rendezvous<>, T0> make_event(T0& x0);
238 inline preevent<rendezvous<> > make_event();
239#endif
240#if TAMER_HAVE_PREEVENT
241 template <typename T0>
242 inline preevent<rendezvous<>, T0> make_preevent(T0& x0);
243 inline preevent<rendezvous<> > make_preevent();
244#endif
245
246 inline bool has_ready() const { return ready_; }
247 inline bool has_waiting() const { return waiting_; }
248 inline bool has_events() const { return ready_ || waiting_; }
249
250 inline bool join() {
251 if (ready_) {
252 (void) pop_ready();
253 return true;
254 } else {
255 return false;
256 }
257 }
258 void clear();
259
260 using tamerpriv::blocking_rendezvous::block;
261};
262
263
264class gather_rendezvous : public tamerpriv::blocking_rendezvous,
265 public zero_argument_rendezvous_tag<gather_rendezvous> {
266 public:
267 inline gather_rendezvous()
268 : blocking_rendezvous(tamerpriv::rgather) {
269 }
270 inline ~gather_rendezvous() {
271 if (waiting_) {
272 clear();
273 }
274 }
275
276 template <typename T0, typename T1, typename T2, typename T3>
277 inline event<T0, T1, T2, T3> make_event(T0& x0, T1& x1, T2& x2, T3& x3);
278 template <typename T0, typename T1, typename T2>
279 inline event<T0, T1, T2> make_event(T0& x0, T1& x1, T2& x2);
280 template <typename T0, typename T1>
281 inline event<T0, T1> make_event(T0& x0, T1& x1);
282#if !TAMER_HAVE_PREEVENT || !TAMER_PREFER_PREEVENT
283 template <typename T0>
284 inline event<T0> make_event(T0& x0);
285 inline event<> make_event();
286#else
287 template <typename T0>
288 inline preevent<gather_rendezvous, T0> make_event(T0& x0);
289 inline preevent<gather_rendezvous> make_event();
290#endif
291#if TAMER_HAVE_PREEVENT
292 template <typename T0>
293 inline preevent<gather_rendezvous, T0> make_preevent(T0& x0);
294 inline preevent<gather_rendezvous> make_preevent();
295#endif
296
297 inline bool has_waiting() const {
298 return waiting_;
299 }
300
301 inline bool join() {
302 return !waiting_;
303 }
304 void clear();
305
306 using tamerpriv::blocking_rendezvous::block;
307
308 private:
309 friend class tamerpriv::abstract_rendezvous;
310};
311
313
315
316namespace tamerpriv {
317template <typename T0 = void, typename T1 = void, typename T2 = void, typename T3 = void>
318class distribute_rendezvous : public functional_rendezvous,
319 public zero_argument_rendezvous_tag<distribute_rendezvous<T0, T1, T2, T3> > {
320 public:
321 typedef tamer::event<T0, T1, T2, T3> event_type;
322 inline distribute_rendezvous();
323 inline ~distribute_rendezvous();
324 static inline void make(event_type& a, event_type b);
325 inline event<T0, T1, T2, T3> make_event();
326 inline int nchildren() const {
327 return nes_;
328 }
329 private:
330 enum { nlocal = 2 };
331 int nes_;
332 int outstanding_;
333 event_type* es_;
334 typename event_type::results_tuple_type vs_;
335 struct alignas(event_type) event_space {
336 char space[sizeof(event_type)];
337 };
338 event_space local_es_[nlocal];
339 static void hook(functional_rendezvous*, simple_event*, bool) TAMER_NOEXCEPT;
340 static void clear_hook(void*);
341 void add(event_type e);
342 static void hard_make(event_type& a, event_type b);
343 bool grow();
344};
345
346template <typename T0, typename T1, typename T2, typename T3>
347inline distribute_rendezvous<T0, T1, T2, T3>::distribute_rendezvous()
348 : functional_rendezvous(rdistribute, hook),
349 nes_(0), outstanding_(0), es_(reinterpret_cast<event_type*>(local_es_)) {
350}
351
352template <typename T0, typename T1, typename T2, typename T3>
353inline distribute_rendezvous<T0, T1, T2, T3>::~distribute_rendezvous() {
354 for (int i = 0; i != nes_; ++i) {
355 es_[i].~event();
356 }
357 if (es_ != reinterpret_cast<event_type*>(local_es_)) {
358 delete[] reinterpret_cast<event_space*>(es_);
359 }
360}
361
362template <typename T0, typename T1, typename T2, typename T3>
363void distribute_rendezvous<T0, T1, T2, T3>::add(event_type e) {
364 if (nes_ >= nlocal && (nes_ & (nes_ - 1)) == 0 && !grow()) {
365 return;
366 }
367 new((void*) &es_[nes_]) event_type(std::move(e));
368 if (es_[nes_].__get_simple()->shared()) {
369 tamerpriv::simple_event::at_trigger(es_[nes_].__get_simple(), clear_hook, this);
370 ++outstanding_;
371 }
372 ++nes_;
373}
374
375template <typename T0, typename T1, typename T2, typename T3>
376inline void distribute_rendezvous<T0, T1, T2, T3>::make(event_type& a, event_type b) {
377 if (!a || !b) {
378 if (!a && b) {
379 a = std::move(b);
380 }
381 } else {
382 hard_make(a, std::move(b));
383 }
384}
385
386template <typename T0, typename T1, typename T2, typename T3>
387void distribute_rendezvous<T0, T1, T2, T3>::hard_make(event_type& a, event_type b) {
388 simple_event* se = a.__get_simple();
389 if (se == b.__get_simple()) {
390 return;
391 }
392 distribute_rendezvous<T0, T1, T2, T3>* r;
393 if (!se->shared() && !se->has_at_trigger()
394 && se->rendezvous()->rtype() == tamerpriv::rdistribute) {
395 r = static_cast<distribute_rendezvous<T0, T1, T2, T3>*>(se->rendezvous());
396 } else {
397 r = new distribute_rendezvous<T0, T1, T2, T3>;
398 r->add(std::move(a));
399 a = r->make_event();
400 }
401 r->add(std::move(b));
402}
403
404template <typename T0, typename T1, typename T2, typename T3>
405bool distribute_rendezvous<T0, T1, T2, T3>::grow() {
406 event_space* new_es = new event_space[nes_ * 2];
407 if (new_es) {
408 event_space* old_es = reinterpret_cast<event_space*>(es_);
409 memcpy(new_es, old_es, sizeof(event_type) * nes_);
410 if (old_es != reinterpret_cast<event_space*>(local_es_)) {
411 delete[] old_es;
412 }
413 es_ = reinterpret_cast<event_type*>(new_es);
414 return true;
415 } else {
416 return false;
417 }
418}
419
420template <typename T0, typename T1, typename T2, typename T3>
421void distribute_rendezvous<T0, T1, T2, T3>::hook(functional_rendezvous* fr,
422 simple_event* x,
423 bool values) TAMER_NOEXCEPT {
424 distribute_rendezvous<T0, T1, T2, T3>* dr =
425 static_cast<distribute_rendezvous<T0, T1, T2, T3>*>(fr);
426 ++dr->outstanding_; // keep memory around until we're done here
427 if (values) {
428 for (int i = 0; i != dr->nes_; ++i) {
429 dr->es_[i].tuple_trigger(dr->vs_);
430 }
431 } else if (!x->unused()) {
432 for (int i = 0; i != dr->nes_; ++i) {
433 dr->es_[i].unblock();
434 }
435 } else {
436 for (int i = 0; i != dr->nes_; ++i) {
437 tamerpriv::simple_event::unuse(dr->es_[i].__release_simple());
438 }
439 }
440 if (--dr->outstanding_ == 0) {
441 delete dr;
442 }
443}
444
445template <typename T0, typename T1, typename T2, typename T3>
446void distribute_rendezvous<T0, T1, T2, T3>::clear_hook(void* arg) {
447 distribute_rendezvous<T0, T1, T2, T3>* dr =
448 static_cast<distribute_rendezvous<T0, T1, T2, T3>*>(arg);
449 if (--dr->outstanding_ == 0) {
450 for (int i = 0; i != dr->nes_; ++i) {
451 if (dr->es_[i])
452 return;
453 }
454 dr->remove_waiting();
455 delete dr;
456 }
457}
458} // namespace tamerpriv
459
461
462
463class tamed_class {
464 public:
465 inline tamed_class() : tamer_closures_() {}
466 inline tamed_class(const tamed_class&) : tamer_closures_() {}
467 inline tamed_class& operator=(const tamed_class&) { return *this; }
468 inline ~tamed_class();
469
470#if TAMER_HAVE_CXX_RVALUE_REFERENCES
471 inline tamed_class(tamed_class&&) : tamer_closures_() {}
472 inline tamed_class& operator=(tamed_class&&) { return *this; }
473#endif
474
475 private:
476 tamerpriv::closure* tamer_closures_;
477
478 friend class tamerpriv::closure;
479};
480
481inline tamed_class::~tamed_class() {
482 while (tamerpriv::closure* tc = tamer_closures_) {
483 tamer_closures_ = tc->tamer_closures_next_;
484 tc->tamer_block_position_ = (unsigned) -1;
485 tc->tamer_closures_pprev_ = 0;
486 tc->unblock();
487 }
488}
489
490
491namespace tamerpriv {
492
493inline void closure::initialize_closure(closure_activator f, ...) {
494 tamer_activator_ = f;
495 tamer_block_position_ = 0;
496 tamer_driver_index_ = 0;
497 tamer_blocked_driver_ = 0;
498 tamer_closures_pprev_ = 0;
499 TAMER_IFTRACE(tamer_location_file_ = 0);
500 TAMER_IFTRACE(tamer_location_line_ = 0);
501 TAMER_IFTRACE(tamer_description_ = 0);
502}
503
504inline void closure::exit_at_destroy(tamed_class* k) {
505 assert(!tamer_closures_pprev_);
506 tamer_closures_pprev_ = &k->tamer_closures_;
507 if ((tamer_closures_next_ = k->tamer_closures_)) {
508 tamer_closures_next_->tamer_closures_pprev_ = &tamer_closures_next_;
509 }
510 k->tamer_closures_ = this;
511}
512
513inline void closure::initialize_closure(closure_activator f, tamed_class* k) {
514 initialize_closure(f);
515 exit_at_destroy(k);
516}
517
518} // namespace tamerpriv
519
520
521class destroy_guard {
522 public:
523 inline destroy_guard(tamerpriv::closure& cl, tamed_class* k);
524 inline ~destroy_guard();
525
526 private:
527 class shiva_closure : public tamerpriv::closure {
528 public:
529 tamerpriv::closure* linked_closure_;
530 };
531 shiva_closure* shiva_;
532
533 destroy_guard(const destroy_guard&) = delete;
534 destroy_guard(destroy_guard&&) = delete;
535 destroy_guard& operator=(const destroy_guard&) = delete;
536 destroy_guard& operator=(destroy_guard&&) = delete;
537 static void activator(tamerpriv::closure*);
538 void birth_shiva(tamerpriv::closure& cl, tamed_class* k);
539};
540
541inline destroy_guard::destroy_guard(tamerpriv::closure& cl, tamed_class* k)
542 : shiva_() {
543 if (!cl.tamer_closures_pprev_) {
544 cl.exit_at_destroy(k);
545 } else {
546 birth_shiva(cl, k);
547 }
548}
549
550inline destroy_guard::~destroy_guard() {
551 if (shiva_) {
552 delete shiva_;
553 }
554}
555
556} // namespace tamer
557#endif /* TAMER__RENDEZVOUS_HH */
A future occurrence.
Definition event.hh:116
A set of watched events.
Definition rendezvous.hh:37
bool has_events() const
Test if any events are ready or waiting.
Definition rendezvous.hh:91
bool has_waiting() const
Test if any events are waiting.
Definition rendezvous.hh:85
bool join(I &eid)
Report the next ready event.
Definition rendezvous.hh:102
~rendezvous()
Destroy rendezvous.
Definition rendezvous.hh:66
bool has_ready() const
Test if any events are ready.
Definition rendezvous.hh:77
void clear()
Remove all events from this rendezvous.
Definition rendezvous.hh:118
event< T0, T1, T2, T3 > make_event(one_argument_rendezvous_tag< R > &r, const I &eid, T0 &x0, T1 &x1, T2 &x2, T3 &x3)
Construct a four-result event on rendezvous r with ID eid.
Definition event.hh:1115
Namespace containing public Tamer classes and functions for the Tamer core.
Definition adapter.hh:17