Tamer
C++ language extensions for event-driven programming
Loading...
Searching...
No Matches
xbase.hh
1#ifndef TAMER_XBASE_HH
2#define TAMER_XBASE_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 <stdexcept>
17#include <string>
18#include <cstdint>
19#include <cassert>
20#include <tamer/autoconf.h>
21namespace tamer {
22
23// Improve error messages from overloaded functions.
24template <typename R> class one_argument_rendezvous_tag {};
25template <typename R> class zero_argument_rendezvous_tag {};
26
27template <typename I = void> class rendezvous;
28template <typename T0 = void, typename T1 = void, typename T2 = void,
29 typename T3 = void> class event;
30#if TAMER_HAVE_PREEVENT
31template <typename R, typename T0 = void> class preevent;
32#endif
33class tamed_class;
34class driver;
35
36class tamer_error : public std::runtime_error { public:
37 explicit tamer_error(const std::string& arg)
38 : runtime_error(arg) {
39 }
40};
41
42
43struct no_result {
44};
45
46
47namespace outcome {
48const int success = 0;
49const int cancel = -ECANCELED;
50const int timeout = -ETIMEDOUT;
51const int signal = -EINTR;
52const int overflow = -EOVERFLOW;
53const int closed = -EPIPE;
54const int destroy = -ECANCELED;
55}
56
57
58namespace tamerpriv {
59
60class simple_event;
61class abstract_rendezvous;
62class blocking_rendezvous;
63class explicit_rendezvous;
64class closure;
65
66class simple_event { public:
67 // DO NOT derive from this class!
68
69 inline simple_event() TAMER_NOEXCEPT;
70 inline simple_event(abstract_rendezvous& r, uintptr_t rid,
71 const char* file, int line) TAMER_NOEXCEPT;
72 inline ~simple_event() TAMER_NOEXCEPT;
73
74 static inline void use(simple_event* e, const char* file = __builtin_FILE(), int line = __builtin_LINE()) TAMER_NOEXCEPT;
75 static inline void unuse(simple_event* e, const char* file = __builtin_FILE(), int line = __builtin_LINE()) TAMER_NOEXCEPT;
76 static inline void unuse_clean(simple_event* e, const char* file = __builtin_FILE(), int line = __builtin_LINE()) TAMER_NOEXCEPT;
77 inline bool unused() const;
78
79 inline explicit operator bool() const;
80 inline bool empty() const;
81 inline abstract_rendezvous* rendezvous() const;
82 inline uintptr_t rid() const;
83 inline simple_event* next() const;
84 inline bool shared() const;
85 inline bool has_at_trigger() const;
86
87 inline const char* file_annotation() const;
88 inline int line_annotation() const;
89
90 inline void simple_trigger(bool values);
91 static void simple_trigger(simple_event* x, bool values) TAMER_NOEXCEPT;
92 void trigger_list_for_remove() TAMER_NOEXCEPT;
93
94 static inline void at_trigger(simple_event* x, simple_event* at_trigger);
95 static inline void at_trigger(simple_event* x, void (*f)(void*), void* arg);
96
97 protected:
98 abstract_rendezvous* _r;
99 uintptr_t _rid;
100 simple_event* _r_next;
101 simple_event** _r_pprev;
102 void (*at_trigger_f_)(void*);
103 void* at_trigger_arg_;
104 unsigned _refcount;
105#if !TAMER_NOTRACE
106 int line_annotation_;
107 const char* file_annotation_;
108#endif
109
110 simple_event(const simple_event&) = delete;
111 simple_event(simple_event&&) = delete;
112 simple_event& operator=(const simple_event&) = delete;
113 simple_event& operator=(const simple_event&&) = delete;
114
115 void unuse_trigger() TAMER_NOEXCEPT;
116 static inline event<> at_trigger_event(void (*f)(void*), void* arg);
117 static void trigger_hook(void* arg);
118 static void hard_at_trigger(simple_event* x, void (*f)(void*), void* arg);
119
120 void print(const char* prefix, const char* filename = nullptr, int line = 0);
121
122 friend class abstract_rendezvous;
123 friend class explicit_rendezvous;
124};
125
126
127enum rendezvous_type {
128 rgather,
129 rexplicit,
130 rfunctional,
131 rdistribute
132};
133
134class abstract_rendezvous {
135 public:
136 explicit abstract_rendezvous(rendezvous_type rtype) TAMER_NOEXCEPT
137 : rtype_(rtype) {
138 }
139 inline ~abstract_rendezvous() TAMER_NOEXCEPT;
140
141 inline rendezvous_type rtype() const {
142 return rendezvous_type(rtype_);
143 }
144
145 bool is_volatile() const;
146 const char* rtype_name() const;
147
148 protected:
149 simple_event* waiting_ = nullptr;
150 uint8_t rtype_;
151
152 inline void remove_waiting() TAMER_NOEXCEPT;
153
154 private:
155 abstract_rendezvous(const abstract_rendezvous&) = delete;
156 abstract_rendezvous(abstract_rendezvous&&) = delete;
157 abstract_rendezvous& operator=(const abstract_rendezvous&) = delete;
158 abstract_rendezvous& operator=(abstract_rendezvous&&) = delete;
159
160 void hard_remove_waiting() TAMER_NOEXCEPT;
161
162 friend class simple_event;
163 friend class driver;
164};
165
166class simple_driver {
167 protected:
168 simple_driver();
169 ~simple_driver();
170
171 inline void add_blocked(closure* c);
172 inline void make_unblocked(closure* c);
173
174 inline closure* pop_unblocked();
175
176 inline unsigned nclosure_slots() const;
177 inline closure* closure_slot(unsigned i) const;
178
179 public:
180 inline bool has_unblocked() const;
181 inline void run_unblocked();
182 inline void clear_unblocked();
183
184 static simple_driver immediate_driver;
185
186 private:
187 struct cptr {
188 closure* c;
189 unsigned next;
190 };
191
192 unsigned ccap_;
193 mutable unsigned cfree_;
194 mutable unsigned cunblocked_;
195 unsigned cunblocked_tail_;
196 cptr* cs_;
197
198 simple_driver(const simple_driver&) = delete;
199 simple_driver(simple_driver&&) = delete;
200 simple_driver& operator=(const simple_driver&) = delete;
201 simple_driver& operator=(simple_driver&&) = delete;
202
203 void add(closure* c);
204 void grow();
205
206 friend class blocking_rendezvous;
207 friend class closure;
208};
209
210class blocking_rendezvous : public abstract_rendezvous {
211 public:
212 explicit inline blocking_rendezvous(rendezvous_type rtype) TAMER_NOEXCEPT;
213 inline ~blocking_rendezvous() TAMER_NOEXCEPT;
214
215 inline bool blocked() const;
216 inline bool volatile_blocked() const;
217
218 inline void block(simple_driver* driver, closure& c, unsigned position);
219 inline void block(closure& c, unsigned position);
220 inline void unblock();
221
222 protected:
223 closure* blocked_closure_;
224
225 void hard_free() TAMER_NOEXCEPT;
226
227 friend class abstract_rendezvous;
228 friend class simple_driver;
229 friend struct driver_timerset;
230};
231
232class explicit_rendezvous : public blocking_rendezvous {
233 public:
234 inline explicit_rendezvous() TAMER_NOEXCEPT
235 : blocking_rendezvous(rexplicit),
236 ready_(), ready_ptail_(&ready_) {
237 }
238 inline ~explicit_rendezvous() {
239 TAMER_DEBUG_ASSERT(!ready_);
240 }
241
242 protected:
243 simple_event* ready_;
244 simple_event** ready_ptail_;
245
246 inline uintptr_t pop_ready() {
247 simple_event* e = ready_;
248 if (!(ready_ = e->_r_next)) {
249 ready_ptail_ = &ready_;
250 }
251 uintptr_t x = e->rid();
252 simple_event::unuse_clean(e);
253 return x;
254 }
255 inline void remove_ready() {
256 while (simple_event* e = ready_) {
257 ready_ = e->_r_next;
258 simple_event::unuse_clean(e);
259 }
260 ready_ptail_ = &ready_;
261 }
262
263 friend class simple_event;
264};
265
266class functional_rendezvous : public abstract_rendezvous {
267 public:
268 typedef void (*hook_type)(functional_rendezvous* fr,
269 simple_event* e, bool values);
270
271 inline functional_rendezvous(void (*f)(functional_rendezvous* fr,
272 simple_event* e, bool values) TAMER_NOEXCEPT)
273 : abstract_rendezvous(rfunctional), f_(f) {
274 }
275 inline functional_rendezvous(rendezvous_type rtype,
276 void (*f)(functional_rendezvous* fr,
277 simple_event* e, bool values) TAMER_NOEXCEPT)
278 : abstract_rendezvous(rtype), f_(f) {
279 }
280 inline ~functional_rendezvous() {
281 remove_waiting();
282 }
283
284 private:
285 void (*f_)(functional_rendezvous* r,
286 simple_event* e, bool values) TAMER_NOEXCEPT;
287
288 friend class simple_event;
289};
290
291typedef void (*closure_activator)(closure*);
292
293class closure {
294 public:
295 typedef closure tamer_closure_type;
296 closure_activator tamer_activator_;
297 unsigned tamer_block_position_;
298 unsigned tamer_driver_index_;
299 simple_driver* tamer_blocked_driver_;
300 closure* tamer_closures_next_;
301 closure** tamer_closures_pprev_;
302#if !TAMER_NOTRACE
303 int tamer_location_line_;
304 const char* tamer_location_file_;
305 std::string* tamer_description_;
306#endif
307 inline ~closure();
308
309 inline bool has_location() const;
310 inline bool has_description() const;
311 inline const char* location_file() const;
312 inline int location_line() const;
313 std::string location() const;
314 inline std::string description() const;
315 std::string location_description() const;
316
317 inline void initialize_closure(closure_activator f, ...);
318 inline void initialize_closure(closure_activator f, tamed_class* k);
319 inline void set_location(const char* file, int line);
320 inline void set_description(std::string description);
321
322 inline void exit_at_destroy(tamed_class* k);
323
324 inline void unblock();
325};
326
327
328template <typename T>
329class closure_owner {
330 public:
331 inline closure_owner(T& c)
332 : c_(&c) {
333 }
334 inline ~closure_owner() {
335 delete c_;
336 }
337 inline void reset() {
338 c_ = 0;
339 }
340 private:
341 T* c_;
342};
343
344template <typename R>
345class rendezvous_owner {
346 public:
347 inline rendezvous_owner(R& r)
348 : r_(&r) {
349 }
350 inline ~rendezvous_owner() {
351 if (r_) {
352 r_->clear();
353 }
354 }
355 inline void reset() {
356 r_ = 0;
357 }
358 private:
359 R* r_;
360};
361
362
363namespace message {
364void event_prematurely_dereferenced(simple_event *e, abstract_rendezvous *r);
365}
366
367
368inline void abstract_rendezvous::remove_waiting() TAMER_NOEXCEPT {
369 if (waiting_) {
370 hard_remove_waiting();
371 }
372}
373
374inline abstract_rendezvous::~abstract_rendezvous() TAMER_NOEXCEPT {
375 TAMER_DEBUG_ASSERT(!waiting_);
376}
377
378
379inline bool simple_driver::has_unblocked() const {
380 while (cunblocked_ && !cs_[cunblocked_].c) {
381 unsigned next = cs_[cunblocked_].next;
382 cs_[cunblocked_].next = cfree_;
383 cfree_ = cunblocked_;
384 cunblocked_ = next;
385 }
386 return cunblocked_ != 0;
387}
388
389inline closure* simple_driver::pop_unblocked() {
390 if (has_unblocked()) {
391 unsigned i = cunblocked_;
392 closure* c = cs_[i].c;
393 cunblocked_ = cs_[i].next;
394 cs_[i].c = 0;
395 cs_[i].next = cfree_;
396 cfree_ = i;
397 return c;
398 } else {
399 return 0;
400 }
401}
402
403inline void simple_driver::run_unblocked() {
404 while (closure* c = pop_unblocked()) {
405 c->tamer_activator_(c);
406 }
407}
408
409inline void simple_driver::clear_unblocked() {
410 while (closure* c = pop_unblocked()) {
411 c->tamer_block_position_ = -1;
412 c->tamer_activator_(c);
413 }
414}
415
416inline void simple_driver::add_blocked(closure* c) {
417#if TAMER_NOTRACE
418 c->tamer_driver_index_ = 0;
419#else
420 add(c);
421#endif
422}
423
424inline void simple_driver::make_unblocked(closure* c) {
425 if (!c->tamer_driver_index_) {
426 add(c);
427 }
428 if (cunblocked_) {
429 cs_[cunblocked_tail_].next = c->tamer_driver_index_;
430 } else {
431 cunblocked_ = c->tamer_driver_index_;
432 }
433 cunblocked_tail_ = c->tamer_driver_index_;
434}
435
436inline unsigned simple_driver::nclosure_slots() const {
437 return ccap_;
438}
439
440inline closure* simple_driver::closure_slot(unsigned i) const {
441 assert(i < ccap_);
442 return cs_[i].c;
443}
444
445
446inline blocking_rendezvous::blocking_rendezvous(rendezvous_type rtype) TAMER_NOEXCEPT
447 : abstract_rendezvous(rtype), blocked_closure_() {
448}
449
450inline blocking_rendezvous::~blocking_rendezvous() TAMER_NOEXCEPT {
451 if (blocked_closure_) {
452 hard_free();
453 }
454}
455
456inline bool blocking_rendezvous::blocked() const {
457 return blocked_closure_ && blocked_closure_->tamer_blocked_driver_;
458}
459
460inline bool blocking_rendezvous::volatile_blocked() const {
461 return blocked_closure_
462 && blocked_closure_->tamer_blocked_driver_
463 && (blocked_closure_->tamer_block_position_ & 1) != 0;
464}
465
466inline void blocking_rendezvous::block(simple_driver* driver, closure& c,
467 unsigned position) {
468 assert(!c.tamer_blocked_driver_);
469 blocked_closure_ = &c;
470 c.tamer_block_position_ = position;
471 c.tamer_blocked_driver_ = driver;
472 driver->add_blocked(&c);
473}
474
475inline void closure::unblock() {
476 if (simple_driver* d = tamer_blocked_driver_) {
477 tamer_blocked_driver_ = 0;
478 if (d != &simple_driver::immediate_driver) {
479 d->make_unblocked(this);
480 } else {
481 tamer_activator_(this);
482 }
483 }
484}
485
486inline void blocking_rendezvous::unblock() {
487 if (closure* cl = blocked_closure_) {
488 blocked_closure_ = 0;
489 cl->unblock();
490 }
491}
492
493
494inline closure::~closure() {
495 if (tamer_closures_pprev_
496 && (*tamer_closures_pprev_ = tamer_closures_next_)) {
497 tamer_closures_next_->tamer_closures_pprev_ = tamer_closures_pprev_;
498 }
499 delete tamer_description_;
500}
501
502inline bool closure::has_location() const {
503 return tamer_location_file_ || tamer_location_line_;
504}
505
506inline bool closure::has_description() const {
507 return tamer_description_ && !tamer_description_->empty();
508}
509
510inline void closure::set_location(const char* file, int line) {
511 TAMER_IFTRACE(tamer_location_file_ = file);
512 TAMER_IFTRACE(tamer_location_line_ = line);
513 TAMER_IFNOTRACE((void) file, (void) line);
514}
515
516inline void closure::set_description(std::string description) {
517#if !TAMER_NOTRACE
518 if (tamer_description_) {
519 *tamer_description_ = std::move(description);
520 } else if (!description.empty()) {
521 tamer_description_ = new std::string(std::move(description));
522 }
523#else
524 (void) description;
525#endif
526}
527
528inline const char* closure::location_file() const {
529 return TAMER_IFTRACE_ELSE(tamer_location_file_, 0);
530}
531
532inline int closure::location_line() const {
533 return TAMER_IFTRACE_ELSE(tamer_location_line_, 0);
534}
535
536inline std::string closure::description() const {
537#if !TAMER_NOTRACE
538 if (tamer_description_) {
539 return *tamer_description_;
540 }
541#endif
542 return std::string();
543}
544
545
546inline simple_event::simple_event() TAMER_NOEXCEPT
547 : _r(0), _refcount(1) TAMER_IFTRACE(, file_annotation_(0)) {
548#if TAMER_DEBUG && TAMER_DEBUG_LEVEL > 1
549 print("create");
550#endif
551}
552
553inline simple_event::simple_event(abstract_rendezvous& r, uintptr_t rid,
554 const char* file, int line) TAMER_NOEXCEPT
555 : _r(&r), _rid(rid), _r_next(r.waiting_), _r_pprev(&r.waiting_),
556 at_trigger_f_(0), at_trigger_arg_(0), _refcount(1)
557 TAMER_IFTRACE(, line_annotation_(line), file_annotation_(file)) {
558 if (r.waiting_) {
559 r.waiting_->_r_pprev = &_r_next;
560 }
561 r.waiting_ = this;
562 TAMER_IFNOTRACE((void) file, (void) line);
563#if TAMER_DEBUG && TAMER_DEBUG_LEVEL > 1
564 print("create", file, line);
565#endif
566}
567
568inline simple_event::~simple_event() TAMER_NOEXCEPT {
569 TAMER_DEBUG_ASSERT(!_r);
570#if TAMER_DEBUG && TAMER_DEBUG_LEVEL > 1
571 print("destroy");
572#endif
573}
574
575inline void simple_event::use(simple_event* e, const char*, int) TAMER_NOEXCEPT {
576 if (e) {
577 ++e->_refcount;
578 }
579}
580
581inline void simple_event::unuse(simple_event* e, const char*, int) TAMER_NOEXCEPT {
582 if (e) {
583 --e->_refcount;
584 if (e->_refcount == 0) {
585 e->unuse_trigger();
586 }
587 }
588}
589
590inline void simple_event::unuse_clean(simple_event* e, const char*, int) TAMER_NOEXCEPT {
591 if (e) {
592 --e->_refcount;
593 if (e->_refcount == 0) {
594 delete e;
595 }
596 }
597}
598
599inline bool simple_event::unused() const {
600 return _refcount == 0;
601}
602
603inline simple_event::operator bool() const {
604 return _r;
605}
606
607inline bool simple_event::empty() const {
608 return !_r;
609}
610
611inline abstract_rendezvous *simple_event::rendezvous() const {
612 return _r;
613}
614
615inline uintptr_t simple_event::rid() const {
616 return _rid;
617}
618
619inline simple_event *simple_event::next() const {
620 return _r_next;
621}
622
623inline bool simple_event::shared() const {
624 return _r && _refcount > 1;
625}
626
627inline bool simple_event::has_at_trigger() const {
628 return at_trigger_f_;
629}
630
631inline const char* simple_event::file_annotation() const {
632#if !TAMER_NOTRACE
633 return file_annotation_;
634#else
635 return nullptr;
636#endif
637}
638
639inline int simple_event::line_annotation() const {
640#if !TAMER_NOTRACE
641 return line_annotation_;
642#else
643 return 0;
644#endif
645}
646
647inline void simple_event::simple_trigger(bool values) {
648 simple_trigger(this, values);
649}
650
651inline void simple_event::at_trigger(simple_event* x, simple_event* at_e) {
652 if (at_e) {
653 at_trigger(x, trigger_hook, at_e);
654 }
655}
656
657inline void simple_event::at_trigger(simple_event* x, void (*f)(void*),
658 void* arg) {
659 if (x && *x && !x->at_trigger_f_) {
660 x->at_trigger_f_ = f;
661 x->at_trigger_arg_ = arg;
662 } else {
663 hard_at_trigger(x, f, arg);
664 }
665}
666
667template <typename T> struct rid_cast {
668 static inline uintptr_t in(T x) TAMER_NOEXCEPT {
669 return static_cast<uintptr_t>(x);
670 }
671 static inline T out(uintptr_t x) TAMER_NOEXCEPT {
672 return static_cast<T>(x);
673 }
674};
675
676template <typename T> struct rid_cast<T *> {
677 static inline uintptr_t in(T *x) TAMER_NOEXCEPT {
678 return reinterpret_cast<uintptr_t>(x);
679 }
680 static inline T *out(uintptr_t x) TAMER_NOEXCEPT {
681 return reinterpret_cast<T *>(x);
682 }
683};
684
685} // namespace tamerpriv
686} // namespace tamer
687#endif /* TAMER_BASE_HH */
A future occurrence.
Definition event.hh:116
A set of watched events.
Definition rendezvous.hh:37
Definition rendezvous.hh:463
Namespace containing public Tamer classes and functions for the Tamer core.
Definition adapter.hh:17