Zth (libzth)
Loading...
Searching...
No Matches
sync.h
Go to the documentation of this file.
1#ifndef ZTH_SYNC_H
2#define ZTH_SYNC_H
3/*
4 * SPDX-FileCopyrightText: 2019-2026 Jochem Rutgers
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 */
8
18#include <libzth/macros.h>
19
20#ifdef __cplusplus
21
22# include <libzth/allocator.h>
23# include <libzth/fiber.h>
24# include <libzth/list.h>
25# include <libzth/util.h>
26# include <libzth/worker.h>
27
28# include <new>
29
30# ifdef ZTH_USE_VALGRIND
31# include <valgrind/memcheck.h>
32# endif
33
34# if __cplusplus >= 201103L && ZTH_HAVE_EXCEPTIONS
35# include <exception>
36# define ZTH_FUTURE_EXCEPTION
37# endif
38
39# if __cplusplus >= 201703L
40# include <tuple>
41# endif
42
43namespace zth {
44
45template <typename Impl, typename T>
47public:
48 constexpr14 T& operator*() const noexcept
49 {
50 zth_assert(impl().get());
51 // cppcheck-suppress nullPointerRedundantCheck
52 return *impl().get();
53 }
54
55 constexpr14 T* operator->() const noexcept
56 {
57 zth_assert(impl().get());
58 return impl().get();
59 }
60
61private:
62 Impl const& impl() const noexcept
63 {
64 return static_cast<Impl const&>(*this);
65 }
66};
67
68template <typename Impl>
69class SharedPointerOps<Impl, void> {
70public:
71};
72
73template <typename T>
74class SharedPointer : public SharedPointerOps<SharedPointer<T>, T> {
75public:
76 typedef T type;
77
78 // cppcheck-suppress noExplicitConstructor
79 constexpr14 SharedPointer(T* object = nullptr) noexcept
80 : m_object(object)
81 {
82 if(m_object)
83 m_object->used();
84 }
85
87 : m_object(p.get())
88 {
89 if(m_object)
90 m_object->used();
91 }
92
93 ~SharedPointer() noexcept
94 {
95 reset();
96 }
97
98 void reset(T* object = nullptr)
99 {
100 if(object)
101 object->used();
102 if(m_object)
103 m_object->unused();
104 m_object = object;
105 }
106
108 {
109 reset(object);
110 return *this;
111 }
112
114 {
115 reset(p.get());
116 return *this;
117 }
118
119# if __cplusplus >= 201103L
121 : m_object()
122 {
123 *this = std::move(p);
124 }
125
127 {
128 reset();
129 m_object = p.release();
130 return *this;
131 }
132# endif
133
134 constexpr type* get() const noexcept
135 {
136 return m_object;
137 }
138
139 constexpr operator type*() const noexcept
140 {
141 return get();
142 }
143
145 {
146 type* object = get();
147 m_object = nullptr;
148 return object;
149 }
150
151 operator bool() const noexcept
152 {
153 return get() != nullptr;
154 }
155
156private:
157 type* m_object;
158};
159
160template <typename Impl, typename T>
162public:
163 constexpr14 T& get() const noexcept
164 {
165 zth_assert(impl().valid());
166 return *impl().m_object.get();
167 }
168
169 constexpr operator T&() const noexcept
170 {
171 return get();
172 }
173
174 constexpr14 decltype(**static_cast<T*>(nullptr)) operator*() const
175 {
176 return *get();
177 }
178
179 constexpr14 decltype(static_cast<T*>(nullptr)->operator->()) operator->() const noexcept
180 {
181 return get().operator->();
182 }
183
184private:
185 Impl const& impl() const noexcept
186 {
187 return static_cast<Impl const&>(*this);
188 }
189};
190
191template <typename Impl>
192class SharedReferenceOps<Impl, void> {
193public:
194};
195
196template <typename T>
197class SharedReference : public SharedReferenceOps<SharedReference<T>, T> {
198public:
201 friend class SharedReferenceOps<SharedReference<T>, T>;
202
204 : m_object()
205 {}
206
207 // cppcheck-suppress noExplicitConstructor
209 : m_object(&object)
210 {}
211
213 : m_object(p.m_object)
214 {}
215
216 // cppcheck-suppress noExplicitConstructor
218 : m_object(p)
219 {}
220
222
223 void reset()
224 {
225 m_object.reset();
226 }
227
229 {
230 m_object = p.m_object;
231 return *this;
232 }
233
234# if __cplusplus >= 201103L
235 // cppcheck-suppress noExplicitConstructor
237 : m_object(std::move(p))
238 {}
239
241 : m_object()
242 {
243 *this = std::move(p);
244 }
245
247 {
248 m_object = std::move(p.m_object);
249 return *this;
250 }
251
252 constexpr14 operator SharedPointer<type>() && noexcept
253 {
254 return std::move(m_object);
255 }
256# endif
257
259 {
260 return m_object;
261 }
262
263 constexpr14 bool valid() const noexcept
264 {
265 return m_object.get();
266 }
267
268private:
269 SharedPointer_type m_object;
270};
271
272class SynchronizerBase : public RefCounted, public UniqueID<SynchronizerBase> {
274protected:
275 explicit SynchronizerBase(cow_string const& name = "Synchronizer")
276 : UniqueID(Config::NamedSynchronizer ? name.str() : string())
277 {}
278
279# if __cplusplus >= 201103L
281 : UniqueID(Config::NamedSynchronizer ? std::move(name).str() : string())
282 {}
283# endif
284
285public:
286 virtual ~SynchronizerBase() noexcept override
287 {
288 zth_dbg(sync, "[%s] Destruct", id_str());
289 }
290
291protected:
293
294 virtual queue_type& queue(size_t q = 0) = 0;
295
296 queue_type::iterator enqueue(Listable& item, size_t q = 0) noexcept
297 {
298 return queue(q).push_back(item);
299 }
300
301 void block(size_t q = 0)
302 {
303 Worker& w = currentWorker();
304 Fiber* f = w.currentFiber();
305 if(unlikely(!f))
307
308 zth_dbg(sync, "[%s] Block %s", id_str(), f->id_str());
309 w.release(*f);
310 enqueue(*f, q);
311 f->nap(Timestamp::null());
312 w.schedule();
313 }
314
319 bool unblock(Fiber& f, size_t q = 0, bool prio = false) noexcept
320 {
321 queue_type& queue_ = queue(q);
322 if(!queue_.contains(f))
323 return false;
324
325 wakeup(f, queue_.erase(f), prio, q);
326 return true;
327 }
328
329 Listable* unblockFirst(size_t q = 0, bool prio = false) noexcept
330 {
331 queue_type& queue_ = queue(q);
332 if(queue_.empty())
333 return nullptr;
334
335 Listable& l = queue_.front();
336 wakeup(l, queue_.pop_front(), prio, q);
337 return &l;
338 }
339
340 bool unblockAll(size_t q = 0, bool prio = false) noexcept
341 {
342 queue_type& queue_ = queue(q);
343 if(queue_.empty())
344 return false;
345
346 while(!queue_.empty()) {
347 Listable& f = queue_.front();
348 wakeup(f, queue_.pop_front(), prio, q);
349 }
350 return true;
351 }
352
353 virtual void
355 size_t UNUSED_PAR(q)) noexcept
356 {
357 // Synchronizer only handles Fibers. Other types could be implemented in a derived
358 // class based on the user parameter.
360 Fiber& f = static_cast<Fiber&>(item);
361
362 Worker& w = currentWorker();
363
364 zth_dbg(sync, "[%s] Unblock %s", id_str(), f.id_str());
365 f.wakeup();
366 w.add(&f, prio);
367 }
368
369 class AlarmClock : public TimedWaitable {
371 public:
374 SynchronizerBase& synchronizer, size_t q, Fiber& fiber,
375 Timestamp const& timeout) noexcept
376 : base(timeout)
377 , m_synchronizer(synchronizer)
378 , m_q(q)
379 , m_fiber(fiber)
380 , m_rang()
381 {}
382
383 virtual ~AlarmClock() noexcept override is_default
384
385 virtual bool poll(Timestamp const& now = Timestamp::now()) noexcept override
386 {
387 if(!base::poll(now))
388 return false;
389
390 zth_dbg(sync, "[%s] %s timed out", m_synchronizer.id_str(),
391 m_fiber.id_str());
392 m_rang = m_synchronizer.unblock(m_fiber, m_q);
393 return true;
394 }
395
396 bool rang() const noexcept
397 {
398 return m_rang;
399 }
400
401 private:
402 SynchronizerBase& m_synchronizer;
403 size_t m_q;
404 Fiber& m_fiber;
405 bool m_rang;
406 };
407
408 friend class AlarmClock;
409
414 bool
415 blockUntil(Timestamp const& timeout, Timestamp const& now = Timestamp::now(), size_t q = 0)
416 {
417 if(timeout <= now)
418 // Immediate timeout.
419 return true;
420
421 return block_(timeout, now, q);
422 }
423
428 bool
429 blockFor(TimeInterval const& timeout, Timestamp const& now = Timestamp::now(), size_t q = 0)
430 {
431 if(timeout.isNegative() || timeout.isNull())
432 // Immediate timeout.
433 return true;
434
435 return block_(now + timeout, now, q);
436 }
437
438private:
443 bool block_(Timestamp const& timeout, Timestamp const& now, size_t q = 0)
444 {
445 Worker& w = currentWorker();
446 Fiber* f = w.currentFiber();
447 if(unlikely(!f))
449
450 zth_dbg(sync, "[%s] Block %s with timeout", id_str(), f->id_str());
451 w.release(*f);
452 queue(q).push_back(*f);
453 f->nap(Timestamp::null());
454
455 AlarmClock a(*this, q, *f, timeout);
456 w.waiter().scheduleTask(a);
457 w.schedule(nullptr, now);
458
459 w.waiter().unscheduleTask(a);
460 return !a.rang();
461 }
462};
463
464template <size_t Size = 1>
467public:
469
471
472 explicit Synchronizer(cow_string const& name)
474 {}
475
476# if __cplusplus >= 201103L
478 : SynchronizerBase(std::move(name))
479 {}
480# endif // C++11
481
482 virtual ~Synchronizer() noexcept override
483 {
484 for(size_t i = 0; i < Size; i++)
485 zth_assert(m_queue[i].empty());
486 }
487
488protected:
490
491 virtual queue_type& queue(size_t q) final
492 {
493 zth_assert(q < Size);
494 return m_queue[q];
495 }
496
497private:
498 queue_type m_queue[Size];
499};
500
505class Mutex : public Synchronizer<> {
507public:
508 explicit Mutex(cow_string const& name = "Mutex")
510 , m_locked()
511 {}
512
513# if __cplusplus >= 201103L
515 : Synchronizer(std::move(name))
516 , m_locked()
517 {}
518# endif
519
520 virtual ~Mutex() noexcept override is_default
521
522 void lock()
523 {
524 while(unlikely(m_locked))
525 block();
526 m_locked = true;
527 zth_dbg(sync, "[%s] Locked", id_str());
528 }
529
530 bool trylock() noexcept
531 {
532 if(m_locked)
533 return false;
534 m_locked = true;
535 zth_dbg(sync, "[%s] Locked", id_str());
536 return true;
537 }
538
539 bool trylock(Timestamp const& timeout)
540 {
541 while(unlikely(m_locked))
542 if(!blockUntil(timeout))
543 return false;
544
545 m_locked = true;
546 zth_dbg(sync, "[%s] Locked", id_str());
547 return true;
548 }
549
550 void unlock() noexcept
551 {
552 zth_assert(m_locked);
553 zth_dbg(sync, "[%s] Unlocked", id_str());
554 m_locked = false;
555 unblockFirst();
556 }
557
558private:
559 bool m_locked;
560};
561
566class Locked {
568public:
569 explicit Locked(Mutex& mutex)
570 : m_mutex(&mutex)
571 {
572 m_mutex->lock();
573 }
574
576 {
577 if(m_mutex)
578 m_mutex->unlock();
579 }
580
581# if __cplusplus >= 201103L
582 Locked(Locked const&) = delete;
583 Locked& operator=(Locked const&) = delete;
584
585 Locked(Locked&& l) noexcept
586 : m_mutex{}
587 {
588 *this = std::move(l);
589 }
590
591 Locked& operator=(Locked&& l) noexcept
592 {
593 if(m_mutex)
594 m_mutex->unlock();
595
596 m_mutex = l.m_mutex;
597 l.m_mutex = nullptr;
598 return *this;
599 }
600# else // Pre C++11
601private:
602 Locked(Locked const&);
603 Locked& operator=(Locked const&);
604# endif // Pre C++11
605
606private:
607 Mutex* m_mutex;
608};
609
614class Semaphore : public Synchronizer<> {
616public:
617 typedef unsigned int count_type;
618
619 explicit Semaphore(count_type init = 0, cow_string const& name = "Semaphore")
621 , m_count(init)
622 , m_unblockAll()
623 {}
624
625# if __cplusplus >= 201103L
627 : Synchronizer(std::move(name))
628 , m_count(init)
629 , m_unblockAll()
630 {}
631# endif
632
633 virtual ~Semaphore() noexcept override is_default
634
635 void acquire(count_type count = 1)
636 {
637 while(m_count < count) {
638 if(count > 1)
639 m_unblockAll = true;
640
641 block();
642 }
643
644 m_count -= count;
645 zth_dbg(sync, "[%s] Acquired %u", id_str(), count);
646
647 if(m_count > 0 && !m_unblockAll) {
648 // There is more to acquire. Wake the next in line.
649 unblockFirst();
650 }
651 }
652
653 void release(count_type count = 1) noexcept
654 {
655 zth_assert(m_count + count >= m_count); // ...otherwise it wrapped around, which is
656 // probably not want you wanted...
657
658 if(unlikely(m_count + count < m_count))
659 // wrapped around, saturate
660 m_count = std::numeric_limits<count_type>::max();
661 else
662 m_count += count;
663
664 zth_dbg(sync, "[%s] Released %u", id_str(), count);
665
666 if(likely(m_count > 0)) {
667 if(!m_unblockAll) {
668 // As some fibers may be waiting for just one unit, and others for
669 // multiple, let them all try to acquire what they need.
670 unblockFirst();
671 } else if(!unblockAll()) {
672 // Nobody was waiting anymore.
673 m_unblockAll = false;
674 }
675 }
676 }
677
678 count_type value() const noexcept
679 {
680 return m_count;
681 }
682
683private:
684 count_type m_count;
685 bool m_unblockAll;
686};
687
692class Signal : public Synchronizer<> {
694public:
695 explicit Signal(cow_string const& name = "Signal")
697 , m_signalled()
698 {}
699
700# if __cplusplus >= 201103L
702 : Synchronizer(std::move(name))
703 , m_signalled()
704 {}
705# endif
706
707 virtual ~Signal() noexcept override is_default
708
709 void wait()
710 {
711 if(!m_signalled) {
712 block();
713 } else {
714 // Do a yield() here, as one might rely on the signal to block
715 // regularly when the signal is used in a loop (see daemon
716 // pattern).
717 yield();
718 }
719
720 if(m_signalled > 0)
721 m_signalled--;
722 }
723
724 bool wait(Timestamp const& timeout, Timestamp const& now = Timestamp::now())
725 {
726 if(!m_signalled) {
727 if(!blockUntil(timeout, now))
728 // Timeout.
729 return false;
730 } else
731 yield();
732
733 if(m_signalled > 0)
734 m_signalled--;
735
736 // Got signalled.
737 return true;
738 }
739
740 bool wait(TimeInterval const& timeout, Timestamp const& now = Timestamp::now())
741 {
742 return wait(now + timeout, now);
743 }
744
745 void signal(bool queue = true, bool queueEveryTime = false) noexcept
746 {
747 zth_dbg(sync, "[%s] Signal", id_str());
748 if(!unblockFirst() && queue && m_signalled >= 0) {
749 if(m_signalled == 0 || queueEveryTime)
750 m_signalled++;
751 zth_assert(m_signalled > 0); // Otherwise, it wrapped around, which is
752 // probably not what you want.
753 }
754 }
755
756 void signalAll(bool queue = true) noexcept
757 {
758 zth_dbg(sync, "[%s] Signal all", id_str());
759 unblockAll();
760 if(queue)
761 m_signalled = -1;
762 }
763
764 void reset() noexcept
765 {
766 m_signalled = 0;
767 }
768
769private:
770 int m_signalled;
771};
772
773template <typename T>
774class Optional {
776public:
777 typedef T type;
778
779 // cppcheck-suppress[uninitMemberVar,noExplicitConstructor]
780 Optional() noexcept
781 : m_valid()
782 {
783 init();
784 }
785
786 ~Optional() noexcept
787 {
788 deinit();
789 }
790
791 bool valid() const noexcept
792 {
793 return m_valid
794# ifdef ZTH_FUTURE_EXCEPTION
795 || m_exception
796# endif // ZTH_FUTURE_EXCEPTION
797 ;
798 }
799
800 operator bool() const noexcept
801 {
802 return valid();
803 }
804
805 void reset() noexcept
806 {
807 unuse();
808 }
809
810 // cppcheck-suppress[uninitMemberVar,noExplicitConstructor]
812 : m_valid()
813 {
814 init();
815 set(value);
816 }
817
818 void set(type const& value = type()) noexcept
819 {
820 unuse();
821 use();
822 new(m_data) type(value);
823 m_valid = true;
824 }
825
826 Optional& operator=(type const& value) noexcept
827 {
828 set(value);
829 return *this;
830 }
831
832# if __cplusplus >= 201103L
833 // cppcheck-suppress[uninitMemberVar,noExplicitConstructor]
834 Optional(type&& value) noexcept
835 : m_valid{true}
836 {
837 use();
838 new(m_data) type{std::move(value)};
839 }
840
841 void set(type&& value) noexcept
842 {
843 unuse();
844 use();
845 new(m_data) type{std::move(value)};
846 m_valid = true;
847 }
848
850 {
851 set(std::move(value));
852 return *this;
853 }
854# endif // C++11
855
856# ifdef ZTH_FUTURE_EXCEPTION
857 // cppcheck-suppress uninitMemberVar
858 Optional(std::exception_ptr exc) noexcept
859 : m_valid()
860 , m_exception(exc)
861 {
862 init();
863 }
864
865 void set(std::exception_ptr exception) noexcept
866 {
867 unuse();
868 m_exception = std::move(exception);
869 }
870
871 Optional& operator=(std::exception_ptr value) noexcept
872 {
873 set(value);
874 return *this;
875 }
876
878 {
879 zth_assert(valid());
880
881 if(m_exception)
882 std::rethrow_exception(m_exception);
883
884 void* p = m_data;
885 return *static_cast<type*>(p);
886 }
887
888 type const& value() const LREF_QUALIFIED
889 {
890 zth_assert(valid());
891
892 if(m_exception)
893 std::rethrow_exception(m_exception);
894
895 void const* p = m_data;
896 return *static_cast<type const*>(p);
897 }
898
899 std::exception_ptr exception() const noexcept
900 {
901 return m_exception;
902 }
903
904# if __cplusplus >= 201103L
905 type&& value() &&
906 {
907 zth_assert(valid());
908
909 if(m_exception)
910 std::rethrow_exception(m_exception);
911
912 void* p = m_data;
913 return std::move(*static_cast<type*>(p));
914 }
915# endif // C++11
916# else // !ZTH_FUTURE_EXCEPTION
918 {
919 zth_assert(valid());
920
921 void* p = m_data;
922 return *static_cast<type*>(p);
923 }
924
925 type const& value() const LREF_QUALIFIED noexcept
926 {
927 zth_assert(valid());
928
929 void const* p = m_data;
930 return *static_cast<type const*>(p);
931 }
932
933# if __cplusplus >= 201103L
934 type&& value() && noexcept
935 {
936 zth_assert(valid());
937
938 void* p = m_data;
939 return std::move(*static_cast<type*>(p));
940 }
941# endif // C++11
942# endif // !ZTH_FUTURE_EXCEPTION
943
944private:
945 void init() noexcept
946 {
947# ifdef ZTH_USE_VALGRIND
948 VALGRIND_MAKE_MEM_NOACCESS(m_data, sizeof(m_data));
949# endif
950 }
951
952 void use() noexcept
953 {
954# ifdef ZTH_USE_VALGRIND
955 VALGRIND_MAKE_MEM_UNDEFINED(m_data, sizeof(m_data));
956# endif
957 }
958
959 void unuse() noexcept
960 {
961# ifdef ZTH_FUTURE_EXCEPTION
962 if(m_exception)
963 m_exception = nullptr;
964# endif // ZTH_FUTURE_EXCEPTION
965
966 if(m_valid) {
967 value().~type();
968 m_valid = false;
969# ifdef ZTH_USE_VALGRIND
970 VALGRIND_MAKE_MEM_NOACCESS(m_data, sizeof(m_data));
971# endif
972 }
973 }
974
975 void deinit() noexcept
976 {
977 if(m_valid) {
978 value().~type();
979# ifdef ZTH_USE_VALGRIND
980 VALGRIND_MAKE_MEM_UNDEFINED(m_data, sizeof(m_data));
981# endif
982 }
983 }
984
985private:
986 alignas(type) char m_data[sizeof(type)];
987 bool m_valid;
988# ifdef ZTH_FUTURE_EXCEPTION
989 std::exception_ptr m_exception;
990# endif // ZTH_FUTURE_EXCEPTION
991};
992
993template <>
994class Optional<void> {
996public:
997 typedef void type;
998
999 // cppcheck-suppress noExplicitConstructor
1000 Optional(bool set = false) noexcept
1001 : m_set(set)
1002 {}
1003
1004 bool valid() const noexcept
1005 {
1006 return m_set
1007# ifdef ZTH_FUTURE_EXCEPTION
1008 || m_exception
1009# endif // ZTH_FUTURE_EXCEPTION
1010 ;
1011 }
1012
1013 void reset() noexcept
1014 {
1015 m_set = false;
1016# ifdef ZTH_FUTURE_EXCEPTION
1017 m_exception = nullptr;
1018# endif // ZTH_FUTURE_EXCEPTION
1019 }
1020
1021 void set() noexcept
1022 {
1023 m_set = true;
1024 }
1025
1026# ifdef ZTH_FUTURE_EXCEPTION
1027 Optional(std::exception_ptr exc) noexcept
1028 : m_exception(exc)
1029 , m_set()
1030 {}
1031
1032 void set(std::exception_ptr exception) noexcept
1033 {
1034 m_exception = std::move(exception);
1035 }
1036
1037 void value() const
1038 {
1039 zth_assert(valid());
1040
1041 if(m_exception)
1042 std::rethrow_exception(m_exception);
1043 }
1044
1045 std::exception_ptr exception() const noexcept
1046 {
1047 return m_exception;
1048 }
1049# else // !ZTH_FUTURE_EXCEPTION
1050 void value() noexcept
1051 {
1052 zth_assert(valid());
1053 }
1054# endif // !ZTH_FUTURE_EXCEPTION
1055
1056private:
1057# ifdef ZTH_FUTURE_EXCEPTION
1058 std::exception_ptr m_exception;
1059# endif // ZTH_FUTURE_EXCEPTION
1060 bool m_set;
1061};
1062
1067template <typename T = void>
1068class Future : public Synchronizer<> {
1070public:
1071 typedef T type;
1074
1075 explicit Future(cow_string const& name = "Future")
1077 {}
1078
1079# if __cplusplus >= 201103L
1081 : Synchronizer{std::move(name)}
1082 {}
1083# endif
1084
1085 virtual ~Future() noexcept override is_default
1086
1087 bool valid() const noexcept
1088 {
1089 return m_value.valid();
1090 }
1091
1092 operator bool() const noexcept
1093 {
1094 return valid();
1095 }
1096
1097 void wait()
1098 {
1099 if(!valid())
1100 block();
1101 }
1102
1103 void set(type const& value = type()) noexcept
1104 {
1105 set_prepare();
1106 m_value.set(value);
1107 set_finalize();
1108 }
1109
1110 Future& operator=(type const& value) noexcept
1111 {
1112 set(value);
1113 return *this;
1114 }
1115
1116# if __cplusplus >= 201103L
1117 void set(type&& value) noexcept
1118 {
1119 set_prepare();
1120 m_value.set(std::move(value));
1121 set_finalize();
1122 }
1123
1125 {
1126 set(std::move(value));
1127 return *this;
1128 }
1129# endif
1130
1131# ifdef ZTH_FUTURE_EXCEPTION
1132 void set(std::exception_ptr exception) noexcept
1133 {
1134 set_prepare();
1135 m_value.set(std::move(exception));
1136 set_finalize();
1137 }
1138
1139 Future& operator=(std::exception_ptr value) noexcept
1140 {
1141 set(std::move(value));
1142 return *this;
1143 }
1144
1145 std::exception_ptr exception() const noexcept
1146 {
1147 return m_value.exception();
1148 }
1149# endif // ZTH_FUTURE_EXCEPTION
1150
1152 {
1153 wait();
1154 return m_value.value();
1155 }
1156
1158 {
1159 return value();
1160 }
1161
1163 {
1164 return &value();
1165 }
1166
1167# if __cplusplus >= 201103L
1169 {
1170 wait();
1171 return m_value.value();
1172 }
1173
1175 {
1176 return value();
1177 }
1178# endif
1179
1180private:
1181 void set_prepare() noexcept
1182 {
1183 zth_assert(!valid());
1184 }
1185
1186 void set_finalize() noexcept
1187 {
1188 zth_dbg(sync, "[%s] Set", id_str());
1189 unblockAll();
1190 }
1191
1192private:
1193 Optional<type> m_value;
1194};
1195
1196template <>
1197// cppcheck-suppress noConstructor
1198class Future<void> : public Synchronizer<> {
1200public:
1201 typedef void type;
1202 typedef void indirection_type;
1203 typedef void member_type;
1204
1205 explicit Future(cow_string const& name = "Future")
1207 {}
1208
1209# if __cplusplus >= 201103L
1211 : Synchronizer(std::move(name))
1212 {}
1213# endif
1214
1215 virtual ~Future() noexcept override is_default
1216
1217 bool valid() const noexcept
1218 {
1219 return m_value.valid();
1220 }
1221
1222 operator bool() const noexcept
1223 {
1224 return valid();
1225 }
1226
1227 void wait()
1228 {
1229 if(!valid())
1230 block();
1231 }
1232
1233 void set() noexcept
1234 {
1235 set_prepare();
1236 m_value.set();
1237 set_finalize();
1238 }
1239
1240# ifdef ZTH_FUTURE_EXCEPTION
1241 void set(std::exception_ptr exception) noexcept
1242 {
1243 set_prepare();
1244 m_value.set(std::move(exception));
1245 set_finalize();
1246 }
1247
1248 Future& operator=(std::exception_ptr value) noexcept
1249 {
1250 set(std::move(value));
1251 return *this;
1252 }
1253
1254 std::exception_ptr exception() const noexcept
1255 {
1256 return m_value.exception();
1257 }
1258# endif // ZTH_FUTURE_EXCEPTION
1259
1260 void value()
1261 {
1262 wait();
1263 m_value.value();
1264 }
1265
1267 {
1268 value();
1269 }
1270
1272 {
1273 value();
1274 }
1275
1276private:
1277 void set_prepare() noexcept
1278 {
1279 zth_assert(!valid());
1280 }
1281
1282 void set_finalize() noexcept
1283 {
1284 zth_dbg(sync, "[%s] Set", id_str());
1285 unblockAll();
1286 }
1287
1288private:
1289 Optional<void> m_value;
1290};
1291
1293
1294
1298template <typename T>
1299class Mailbox : public Synchronizer<2> {
1301protected:
1302 enum { Queue_Put = 0, Queue_Take = 1 };
1303
1304public:
1305 typedef T type;
1306 typedef void* assigned_type;
1307
1308 explicit Mailbox(cow_string const& name = "Mailbox")
1310 , m_assigned()
1311 {}
1312
1313# if __cplusplus >= 201103L
1315 : Synchronizer{std::move(name)}
1316 , m_assigned()
1317 {}
1318# endif // C++11
1319
1320 virtual ~Mailbox() noexcept override is_default
1321
1322 bool valid() const noexcept
1323 {
1324 return m_value.valid();
1325 }
1326
1327 operator bool() const noexcept
1328 {
1329 return valid();
1330 }
1331
1332 bool can_put() const noexcept
1333 {
1334 return !valid();
1335 }
1336
1337 bool can_take() const noexcept
1338 {
1339 return valid(static_cast<Listable*>(&currentFiber()));
1340 }
1341
1342protected:
1343 bool valid(assigned_type assigned) const noexcept
1344 {
1345 return valid() && (!m_assigned || m_assigned == assigned);
1346 }
1347
1348public:
1349 void wait()
1350 {
1351 wait(static_cast<Listable*>(&currentFiber()));
1352 }
1353
1354protected:
1355 virtual void wait(assigned_type assigned)
1356 {
1357 while(!valid(assigned))
1358 block((size_t)Queue_Take);
1359 }
1360
1361public:
1363 {
1364 while(valid())
1365 block((size_t)Queue_Put);
1366 }
1367
1368 void put(type const& value)
1369 {
1370 put_prepare();
1371 m_value.set(value);
1372 put_finalize();
1373 }
1374
1375 Mailbox& operator=(type const& value)
1376 {
1377 put(value);
1378 return *this;
1379 }
1380
1381# if __cplusplus >= 201103L
1382 void put(type&& value)
1383 {
1384 put_prepare();
1385 m_value.set(std::move(value));
1386 put_finalize();
1387 }
1388
1390 {
1391 put(std::move(value));
1392 return *this;
1393 }
1394# endif
1395
1396# ifdef ZTH_FUTURE_EXCEPTION
1397 void put(std::exception_ptr exception)
1398 {
1399 put_prepare();
1400 m_value.set(std::move(exception));
1401 put_finalize();
1402 }
1403
1404 Mailbox& operator=(std::exception_ptr value)
1405 {
1406 put(std::move(value));
1407 return *this;
1408 }
1409
1410 std::exception_ptr exception() const noexcept
1411 {
1412 return m_value.exception();
1413 }
1414# endif // ZTH_FUTURE_EXCEPTION
1415
1417 {
1418 return take(static_cast<Listable*>(&zth::currentFiber()));
1419 }
1420
1421protected:
1423 {
1424 take_prepare(assigned);
1425
1426# ifdef ZTH_FUTURE_EXCEPTION
1427 std::exception_ptr exc = m_value.exception();
1428 if(exc) {
1429 take_finalize();
1430 std::rethrow_exception(exc);
1431 }
1432# endif // ZTH_FUTURE_EXCEPTION
1433
1434 type v = m_value.value();
1435 take_finalize();
1436 return v;
1437 }
1438
1439 virtual void
1440 wakeup(Listable& item, queue_type::user_type user, bool prio, size_t q) noexcept final
1441 {
1442 if(q == Queue_Take)
1443 m_assigned = wakeup(item, user, prio);
1444 else
1445 base::wakeup(item, user, prio, q);
1446 }
1447
1448 virtual assigned_type wakeup(Listable& item, queue_type::user_type user, bool prio) noexcept
1449 {
1450 base::wakeup(item, user, prio, Queue_Take);
1451 return &item;
1452 }
1453
1454private:
1455 void put_prepare()
1456 {
1457 wait_empty();
1458 }
1459
1460 void put_finalize() noexcept
1461 {
1462 zth_dbg(sync, "[%s] Put", id_str());
1464 }
1465
1466 void take_prepare(assigned_type assigned)
1467 {
1468 wait(assigned);
1469 }
1470
1471 void take_finalize() noexcept
1472 {
1473 zth_dbg(sync, "[%s] Take", id_str());
1474 m_value.reset();
1476 }
1477
1478private:
1479 Optional<type> m_value;
1480 assigned_type m_assigned;
1481};
1482
1487class Gate : public Synchronizer<> {
1489public:
1490 explicit Gate(size_t count, cow_string const& name = "Gate")
1492 , m_count(count)
1493 , m_current()
1494 {}
1495
1496# if __cplusplus >= 201103L
1498 : Synchronizer(std::move(name))
1499 , m_count(count)
1500 , m_current()
1501 {}
1502# endif
1503
1504 virtual ~Gate() noexcept override is_default
1505
1506 bool pass() noexcept
1507 {
1508 zth_dbg(sync, "[%s] Pass", id_str());
1509 if(++m_current >= count()) {
1510 m_current -= count();
1511 unblockAll();
1512 return true;
1513 } else {
1514 return false;
1515 }
1516 }
1517
1518 void wait()
1519 {
1520 if(!pass())
1521 block();
1522 }
1523
1524 size_t count() const noexcept
1525 {
1526 return m_count;
1527 }
1528
1529 size_t current() const noexcept
1530 {
1531 return m_current;
1532 }
1533
1534private:
1535 size_t const m_count;
1536 size_t m_current;
1537};
1538
1539} // namespace zth
1540
1542 void* p;
1543};
1544
1550EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mutex_init(zth_mutex_t* mutex) noexcept
1551{
1552 if(unlikely(!mutex || mutex->p))
1553 return EINVAL;
1554
1555 try {
1556 mutex->p = static_cast<void*>(new zth::Mutex());
1557 return 0;
1558 } catch(std::bad_alloc const&) {
1559 return ENOMEM;
1560 } catch(...) {
1561 }
1562 return EAGAIN;
1563}
1564
1570EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mutex_destroy(zth_mutex_t* mutex) noexcept
1571{
1572 if(unlikely(!mutex))
1573 return EINVAL;
1574 if(unlikely(!mutex->p))
1575 // Already destroyed.
1576 return 0;
1577
1578 delete static_cast<zth::Mutex*>(mutex->p);
1579 mutex->p = nullptr;
1580 return 0;
1581}
1582
1588EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mutex_lock(zth_mutex_t* mutex) noexcept
1589{
1590 if(unlikely(!mutex || !mutex->p))
1591 return EINVAL;
1592
1593 static_cast<zth::Mutex*>(mutex->p)->lock();
1594 return 0;
1595}
1596
1602EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mutex_trylock(zth_mutex_t* mutex) noexcept
1603{
1604 if(unlikely(!mutex || !mutex->p))
1605 return EINVAL;
1606
1607 return static_cast<zth::Mutex*>(mutex->p)->trylock() ? 0 : EBUSY;
1608}
1609
1615EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mutex_unlock(zth_mutex_t* mutex) noexcept
1616{
1617 if(unlikely(!mutex || !mutex->p))
1618 return EINVAL;
1619
1620 static_cast<zth::Mutex*>(mutex->p)->unlock();
1621 return 0;
1622}
1623
1625 void* p;
1626};
1627
1633EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_sem_init(zth_sem_t* sem, size_t value) noexcept
1634{
1635 if(unlikely(!sem || sem->p))
1636 return EINVAL;
1637
1638 if(value > std::numeric_limits<zth::Semaphore::count_type>::max())
1639 return EDOM;
1640
1641 try {
1642 sem->p = static_cast<void*>(new zth::Semaphore((zth::Semaphore::count_type)value));
1643 return 0;
1644 } catch(std::bad_alloc const&) {
1645 return ENOMEM;
1646 } catch(...) {
1647 }
1648 return EAGAIN;
1649}
1650
1656EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_sem_destroy(zth_sem_t* sem) noexcept
1657{
1658 if(unlikely(!sem))
1659 return EINVAL;
1660 if(unlikely(!sem->p))
1661 // Already destroyed.
1662 return 0;
1663
1664 delete static_cast<zth::Semaphore*>(sem->p);
1665 sem->p = nullptr;
1666 return 0;
1667}
1668
1674EXTERN_C ZTH_EXPORT ZTH_INLINE int
1675zth_sem_getvalue(zth_sem_t* __restrict__ sem, size_t* __restrict__ value) noexcept
1676{
1677 if(unlikely(!sem || !sem->p || !value))
1678 return EINVAL;
1679
1680 *value = static_cast<zth::Semaphore*>(sem->p)->value();
1681 return 0;
1682}
1683
1684# ifndef EOVERFLOW
1685# define EOVERFLOW EAGAIN
1686# endif
1687
1693EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_sem_post(zth_sem_t* sem) noexcept
1694{
1695 if(unlikely(!sem || !sem->p))
1696 return EINVAL;
1697
1698 zth::Semaphore* s = static_cast<zth::Semaphore*>(sem->p);
1699 if(unlikely(s->value() == std::numeric_limits<size_t>::max()))
1700 return EOVERFLOW;
1701
1702 s->release();
1703 return 0;
1704}
1705
1711EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_sem_wait(zth_sem_t* sem) noexcept
1712{
1713 if(unlikely(!sem || !sem->p))
1714 return EINVAL;
1715
1716 static_cast<zth::Semaphore*>(sem->p)->acquire();
1717 return 0;
1718}
1719
1725EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_sem_trywait(zth_sem_t* sem) noexcept
1726{
1727 if(unlikely(!sem || !sem->p))
1728 return EINVAL;
1729
1730 zth::Semaphore* s = static_cast<zth::Semaphore*>(sem->p);
1731 if(unlikely(s->value() == 0))
1732 return EAGAIN;
1733
1734 s->acquire();
1735 return 0;
1736}
1737
1739 void* p;
1740};
1741
1747EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_cond_init(zth_cond_t* cond) noexcept
1748{
1749 if(unlikely(!cond || cond->p))
1750 return EINVAL;
1751
1752 try {
1753 cond->p = static_cast<void*>(new zth::Signal());
1754 return 0;
1755 } catch(std::bad_alloc const&) {
1756 return ENOMEM;
1757 } catch(...) {
1758 }
1759 return EAGAIN;
1760}
1761
1767EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_cond_destroy(zth_cond_t* cond) noexcept
1768{
1769 if(unlikely(!cond))
1770 return EINVAL;
1771 if(unlikely(!cond->p))
1772 // Already destroyed.
1773 return 0;
1774
1775 delete static_cast<zth::Signal*>(cond->p);
1776 cond->p = nullptr;
1777 return 0;
1778}
1779
1785EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_cond_signal(zth_cond_t* cond) noexcept
1786{
1787 if(unlikely(!cond || !cond->p))
1788 return EINVAL;
1789
1790 static_cast<zth::Signal*>(cond->p)->signal();
1791 return 0;
1792}
1793
1799EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_cond_broadcast(zth_cond_t* cond) noexcept
1800{
1801 if(unlikely(!cond || !cond->p))
1802 return EINVAL;
1803
1804 static_cast<zth::Signal*>(cond->p)->signalAll(false);
1805 return 0;
1806}
1807
1813EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_cond_wait(zth_cond_t* cond) noexcept
1814{
1815 if(unlikely(!cond || !cond->p))
1816 return EINVAL;
1817
1818 static_cast<zth::Signal*>(cond->p)->wait();
1819 return 0;
1820}
1821
1823 void* p;
1824};
1825
1827
1833EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_future_init(zth_future_t* future) noexcept
1834{
1835 if(unlikely(!future || future->p))
1836 return EINVAL;
1837
1838 try {
1839 future->p = static_cast<void*>(new zth_future_t_type());
1840 return 0;
1841 } catch(std::bad_alloc const&) {
1842 return ENOMEM;
1843 } catch(...) {
1844 }
1845 return EAGAIN;
1846}
1847
1853EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_future_destroy(zth_future_t* future) noexcept
1854{
1855 if(unlikely(!future))
1856 return EINVAL;
1857 if(unlikely(!future->p))
1858 // Already destroyed.
1859 return 0;
1860
1861 delete static_cast<zth_future_t_type*>(future->p);
1862 future->p = nullptr;
1863 return 0;
1864}
1865
1871EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_future_valid(zth_future_t* future) noexcept
1872{
1873 if(unlikely(!future || !future->p))
1874 return EINVAL;
1875
1876 return static_cast<zth_future_t_type*>(future->p)->valid() ? 0 : EAGAIN;
1877}
1878
1884EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_future_set(zth_future_t* future, uintptr_t value) noexcept
1885{
1886 if(unlikely(!future || !future->p))
1887 return EINVAL;
1888
1889 zth_future_t_type* f = static_cast<zth_future_t_type*>(future->p);
1890 if(f->valid())
1891 return EAGAIN;
1892
1893 f->set(value);
1894 return 0;
1895}
1896
1902EXTERN_C ZTH_EXPORT ZTH_INLINE int
1903zth_future_get(zth_future_t* __restrict__ future, uintptr_t* __restrict__ value) noexcept
1904{
1905 if(unlikely(!future || !future->p || !value))
1906 return EINVAL;
1907
1908 *value = static_cast<zth_future_t_type*>(future->p)->value();
1909 return 0;
1910}
1911
1917EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_future_wait(zth_future_t* future) noexcept
1918{
1919 if(unlikely(!future || !future->p))
1920 return EINVAL;
1921
1922 static_cast<zth_future_t_type*>(future->p)->wait();
1923 return 0;
1924}
1925
1927 void* p;
1928};
1929
1939EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_gate_init(zth_gate_t* gate, size_t count) noexcept
1940{
1941 if(unlikely(!gate || gate->p))
1942 return EINVAL;
1943
1944 try {
1945 gate->p = static_cast<void*>(new zth::Gate(count));
1946 return 0;
1947 } catch(std::bad_alloc const&) {
1948 return ENOMEM;
1949 } catch(...) {
1950 }
1951 return EAGAIN;
1952}
1953
1959EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_gate_destroy(zth_gate_t* gate) noexcept
1960{
1961 if(unlikely(!gate))
1962 return EINVAL;
1963 if(unlikely(!gate->p))
1964 // Already destroyed.
1965 return 0;
1966
1967 delete static_cast<zth::Gate*>(gate->p);
1968 gate->p = nullptr;
1969 return 0;
1970}
1971
1977EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_gate_pass(zth_gate_t* gate) noexcept
1978{
1979 if(unlikely(!gate || !gate->p))
1980 return EINVAL;
1981
1982 return static_cast<zth::Gate*>(gate->p)->pass() ? 0 : EBUSY;
1983}
1984
1990EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_gate_wait(zth_gate_t* gate) noexcept
1991{
1992 if(unlikely(!gate || !gate->p))
1993 return EINVAL;
1994
1995 static_cast<zth::Gate*>(gate->p)->wait();
1996 return 0;
1997}
1998
2000 void* p;
2001};
2002
2004
2010EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mailbox_init(zth_mailbox_t* mailbox) noexcept
2011{
2012 if(unlikely(!mailbox || mailbox->p))
2013 return EINVAL;
2014
2015 try {
2016 mailbox->p = static_cast<void*>(new zth_mailbox_t_type());
2017 return 0;
2018 } catch(std::bad_alloc const&) {
2019 return ENOMEM;
2020 } catch(...) {
2021 }
2022 return EAGAIN;
2023}
2024
2030EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mailbox_destroy(zth_mailbox_t* mailbox) noexcept
2031{
2032 if(unlikely(!mailbox))
2033 return EINVAL;
2034 if(unlikely(!mailbox->p))
2035 // Already destroyed.
2036 return 0;
2037
2038 delete static_cast<zth_mailbox_t_type*>(mailbox->p);
2039 mailbox->p = nullptr;
2040 return 0;
2041}
2042
2048EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mailbox_can_take(zth_mailbox_t* mailbox) noexcept
2049{
2050 if(unlikely(!mailbox || !mailbox->p))
2051 return EINVAL;
2052
2053 return static_cast<zth_mailbox_t_type*>(mailbox->p)->can_take() ? 0 : EAGAIN;
2054}
2055
2061EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mailbox_can_put(zth_mailbox_t* mailbox) noexcept
2062{
2063 if(unlikely(!mailbox || !mailbox->p))
2064 return EINVAL;
2065
2066 return static_cast<zth_mailbox_t_type*>(mailbox->p)->can_put() ? 0 : EAGAIN;
2067}
2068
2075EXTERN_C ZTH_EXPORT ZTH_INLINE int zth_mailbox_put(zth_mailbox_t* mailbox, uintptr_t value) noexcept
2076{
2077 if(unlikely(!mailbox || !mailbox->p))
2078 return EINVAL;
2079
2080 zth_mailbox_t_type* m = static_cast<zth_mailbox_t_type*>(mailbox->p);
2081 m->put(value);
2082 return 0;
2083}
2084
2090EXTERN_C ZTH_EXPORT ZTH_INLINE int
2091zth_mailbox_take(zth_mailbox_t* __restrict__ mailbox, uintptr_t* __restrict__ value) noexcept
2092{
2093 if(unlikely(!mailbox || !mailbox->p || !value))
2094 return EINVAL;
2095
2096 *value = static_cast<zth_mailbox_t_type*>(mailbox->p)->take();
2097 return 0;
2098}
2099
2100
2101#else // !__cplusplus
2102
2103# include <stdint.h>
2104
2105typedef struct {
2106 void* p;
2107} zth_mutex_t;
2108
2109ZTH_EXPORT int zth_mutex_init(zth_mutex_t* mutex);
2110ZTH_EXPORT int zth_mutex_destroy(zth_mutex_t* mutex);
2111ZTH_EXPORT int zth_mutex_lock(zth_mutex_t* mutex);
2112ZTH_EXPORT int zth_mutex_trylock(zth_mutex_t* mutex);
2113ZTH_EXPORT int zth_mutex_unlock(zth_mutex_t* mutex);
2114
2115typedef struct {
2116 void* p;
2117} zth_sem_t;
2118
2119ZTH_EXPORT int zth_sem_init(zth_sem_t* sem, size_t value);
2120ZTH_EXPORT int zth_sem_destroy(zth_sem_t* sem);
2121ZTH_EXPORT int zth_sem_getvalue(zth_sem_t* __restrict__ sem, size_t* __restrict__ value);
2122ZTH_EXPORT int zth_sem_post(zth_sem_t* sem);
2123ZTH_EXPORT int zth_sem_wait(zth_sem_t* sem);
2124ZTH_EXPORT int zth_sem_trywait(zth_sem_t* sem);
2125
2126typedef struct {
2127 void* p;
2128} zth_cond_t;
2129
2130ZTH_EXPORT int zth_cond_init(zth_cond_t* cond);
2131ZTH_EXPORT int zth_cond_destroy(zth_cond_t* cond);
2132ZTH_EXPORT int zth_cond_signal(zth_cond_t* cond);
2133ZTH_EXPORT int zth_cond_broadcast(zth_cond_t* cond);
2134ZTH_EXPORT int zth_cond_wait(zth_cond_t* cond);
2135
2136typedef struct {
2137 void* p;
2138} zth_future_t;
2139
2140ZTH_EXPORT int zth_future_init(zth_future_t* future);
2141ZTH_EXPORT int zth_future_destroy(zth_future_t* future);
2142ZTH_EXPORT int zth_future_valid(zth_future_t* future);
2143ZTH_EXPORT int zth_future_set(zth_future_t* future, uintptr_t value);
2144ZTH_EXPORT int zth_future_get(zth_future_t* __restrict__ future, uintptr_t* __restrict__ value);
2145ZTH_EXPORT int zth_future_wait(zth_future_t* future);
2146
2147typedef struct {
2148 void* p;
2149} zth_gate_t;
2150
2151ZTH_EXPORT int zth_gate_init(zth_gate_t* gate, size_t count);
2152ZTH_EXPORT int zth_gate_destroy(zth_gate_t* gate);
2153ZTH_EXPORT int zth_gate_pass(zth_gate_t* gate);
2154ZTH_EXPORT int zth_gate_wait(zth_gate_t* gate);
2155
2156typedef struct {
2157 void* p;
2159
2160ZTH_EXPORT int zth_mailbox_init(zth_mailbox_t* mailbox);
2161ZTH_EXPORT int zth_mailbox_destroy(zth_mailbox_t* mailbox);
2162ZTH_EXPORT int zth_mailbox_can_take(zth_mailbox_t* mailbox);
2163ZTH_EXPORT int zth_mailbox_can_put(zth_mailbox_t* mailbox);
2164ZTH_EXPORT int zth_mailbox_put(zth_mailbox_t* mailbox, uintptr_t value);
2165ZTH_EXPORT int zth_mailbox_take(zth_mailbox_t* __restrict__ mailbox, uintptr_t* __restrict__ value);
2166
2167#endif // !__cplusplus
2168#endif // ZTH_SYNC_H
The fiber.
Definition fiber.h:49
void wakeup() noexcept
Definition fiber.h:321
void nap(Timestamp const &sleepUntil=Timestamp::null()) noexcept
Definition fiber.h:289
Future(cow_string const &name="Future")
Definition sync.h:1205
void indirection_type
Definition sync.h:1202
Future(cow_string &&name)
Definition sync.h:1210
virtual ~Future() noexcept override=default
member_type operator->()
Definition sync.h:1271
indirection_type operator*()
Definition sync.h:1266
void set() noexcept
Definition sync.h:1233
Fiber-aware future.
Definition sync.h:1068
void set(type &&value) noexcept
Definition sync.h:1117
void set(type const &value=type()) noexcept
Definition sync.h:1103
type * member_type
Definition sync.h:1073
Future & operator=(type &&value) noexcept
Definition sync.h:1124
Future & operator=(type const &value) noexcept
Definition sync.h:1110
type && operator*() &&
Definition sync.h:1174
member_type operator->()
Definition sync.h:1162
Future(cow_string &&name)
Definition sync.h:1080
bool valid() const noexcept
Definition sync.h:1087
indirection_type operator*() &
Definition sync.h:1157
virtual ~Future() noexcept override=default
Future(cow_string const &name="Future")
Definition sync.h:1075
type & value() &
Definition sync.h:1151
type && value() &&
Definition sync.h:1168
void wait()
Definition sync.h:1097
type & indirection_type
Definition sync.h:1072
Fiber-aware barrier/gate.
Definition sync.h:1487
Gate(size_t count, cow_string &&name)
Definition sync.h:1497
size_t current() const noexcept
Definition sync.h:1529
virtual ~Gate() noexcept override=default
size_t count() const noexcept
Definition sync.h:1524
void wait()
Definition sync.h:1518
Gate(size_t count, cow_string const &name="Gate")
Definition sync.h:1490
bool pass() noexcept
Definition sync.h:1506
elem_type::user_type user_type
Definition list.h:96
bool empty() const noexcept
Definition list.h:342
iterator erase(iterator const &pos) noexcept
Definition list.h:407
iterator push_back(elem_type &elem) noexcept
Definition list.h:244
user_type pop_front() noexcept
Definition list.h:320
bool contains(elem_type const &elem) const noexcept
Definition list.h:373
type & front() const noexcept
Definition list.h:285
Mutex RAII, that locks and unlocks the mutex automatically.
Definition sync.h:566
Locked(Locked &&l) noexcept
Definition sync.h:585
Locked(Locked const &)=delete
Locked & operator=(Locked &&l) noexcept
Definition sync.h:591
Locked & operator=(Locked const &)=delete
~Locked()
Definition sync.h:575
Locked(Mutex &mutex)
Definition sync.h:569
Fiber-aware mailbox.
Definition sync.h:1299
virtual assigned_type wakeup(Listable &item, queue_type::user_type user, bool prio) noexcept
Definition sync.h:1448
void put(type const &value)
Definition sync.h:1368
void wait()
Definition sync.h:1349
Mailbox & operator=(type const &value)
Definition sync.h:1375
void wait_empty()
Definition sync.h:1362
Mailbox(cow_string const &name="Mailbox")
Definition sync.h:1308
bool can_put() const noexcept
Definition sync.h:1332
virtual ~Mailbox() noexcept override=default
bool can_take() const noexcept
Definition sync.h:1337
bool valid(assigned_type assigned) const noexcept
Definition sync.h:1343
void put(type &&value)
Definition sync.h:1382
virtual void wait(assigned_type assigned)
Definition sync.h:1355
Mailbox(cow_string &&name)
Definition sync.h:1314
bool valid() const noexcept
Definition sync.h:1322
Mailbox & operator=(type &&value)
Definition sync.h:1389
type take()
Definition sync.h:1416
void * assigned_type
Definition sync.h:1306
type take(assigned_type assigned)
Definition sync.h:1422
virtual void wakeup(Listable &item, queue_type::user_type user, bool prio, size_t q) noexcept final
Definition sync.h:1440
Fiber-aware mutex.
Definition sync.h:505
Mutex(cow_string const &name="Mutex")
Definition sync.h:508
bool trylock(Timestamp const &timeout)
Definition sync.h:539
void lock()
Definition sync.h:522
Mutex(cow_string &&name)
Definition sync.h:514
bool trylock() noexcept
Definition sync.h:530
void unlock() noexcept
Definition sync.h:550
virtual ~Mutex() noexcept override=default
virtual char const * id_str() const noexcept override
Definition util.h:772
string const & name() const noexcept
Definition util.h:746
void reset() noexcept
Definition sync.h:1013
void value() noexcept
Definition sync.h:1050
bool valid() const noexcept
Definition sync.h:1004
Optional(bool set=false) noexcept
Definition sync.h:1000
void set() noexcept
Definition sync.h:1021
type & value() &noexcept
Definition sync.h:917
void reset() noexcept
Definition sync.h:805
bool valid() const noexcept
Definition sync.h:791
void set(type &&value) noexcept
Definition sync.h:841
Optional(type const &value)
Definition sync.h:811
type && value() &&noexcept
Definition sync.h:934
Optional(type &&value) noexcept
Definition sync.h:834
type const & value() const &noexcept
Definition sync.h:925
void set(type const &value=type()) noexcept
Definition sync.h:818
Optional & operator=(type &&value) noexcept
Definition sync.h:849
~Optional() noexcept
Definition sync.h:786
Optional() noexcept
Definition sync.h:780
Optional & operator=(type const &value) noexcept
Definition sync.h:826
Fiber-aware semaphore.
Definition sync.h:614
Semaphore(count_type init, cow_string &&name)
Definition sync.h:626
count_type value() const noexcept
Definition sync.h:678
unsigned int count_type
Definition sync.h:617
void release(count_type count=1) noexcept
Definition sync.h:653
virtual ~Semaphore() noexcept override=default
void acquire(count_type count=1)
Definition sync.h:635
Semaphore(count_type init=0, cow_string const &name="Semaphore")
Definition sync.h:619
~SharedPointer() noexcept
Definition sync.h:93
constexpr SharedPointer(T *object=nullptr) noexcept
Definition sync.h:79
constexpr type * get() const noexcept
Definition sync.h:134
constexpr type * release() noexcept
Definition sync.h:144
constexpr SharedPointer(SharedPointer const &p) noexcept
Definition sync.h:86
void reset(T *object=nullptr)
Definition sync.h:98
SharedPointer & operator=(T *object)
Definition sync.h:107
constexpr SharedPointer & operator=(SharedPointer &&p) noexcept
Definition sync.h:126
SharedPointer & operator=(SharedPointer const &p) noexcept
Definition sync.h:113
constexpr SharedPointer(SharedPointer &&p) noexcept
Definition sync.h:120
constexpr T * operator->() const noexcept
Definition sync.h:55
constexpr T & operator*() const noexcept
Definition sync.h:48
constexpr SharedReference(SharedPointer_type const &p) noexcept
Definition sync.h:217
~SharedReference() noexcept=default
constexpr SharedReference(SharedReference &&p) noexcept
Definition sync.h:240
SharedPointer< T > SharedPointer_type
Definition sync.h:199
constexpr SharedReference(SharedPointer_type &&p) noexcept
Definition sync.h:236
constexpr SharedReference & operator=(SharedReference &&p) noexcept
Definition sync.h:246
constexpr SharedReference(type &object) noexcept
Definition sync.h:208
SharedReference & operator=(SharedReference const &p) noexcept
Definition sync.h:228
constexpr SharedReference() noexcept
Definition sync.h:203
constexpr bool valid() const noexcept
Definition sync.h:263
constexpr SharedReference(SharedReference const &p) noexcept
Definition sync.h:212
SharedPointer_type::type type
Definition sync.h:200
constexpr T & get() const noexcept
Definition sync.h:163
Fiber-aware signal.
Definition sync.h:692
void signal(bool queue=true, bool queueEveryTime=false) noexcept
Definition sync.h:745
void signalAll(bool queue=true) noexcept
Definition sync.h:756
Signal(cow_string &&name)
Definition sync.h:701
void wait()
Definition sync.h:709
bool wait(TimeInterval const &timeout, Timestamp const &now=Timestamp::now())
Definition sync.h:740
Signal(cow_string const &name="Signal")
Definition sync.h:695
bool wait(Timestamp const &timeout, Timestamp const &now=Timestamp::now())
Definition sync.h:724
virtual ~Signal() noexcept override=default
void reset() noexcept
Definition sync.h:764
bool rang() const noexcept
Definition sync.h:396
virtual ~AlarmClock() noexcept override=default
virtual bool poll(Timestamp const &now=Timestamp::now()) noexcept override
Definition sync.h:385
AlarmClock(SynchronizerBase &synchronizer, size_t q, Fiber &fiber, Timestamp const &timeout) noexcept
Definition sync.h:373
queue_type::iterator enqueue(Listable &item, size_t q=0) noexcept
Definition sync.h:296
virtual queue_type & queue(size_t q=0)=0
void block(size_t q=0)
Definition sync.h:301
SynchronizerBase(cow_string const &name="Synchronizer")
Definition sync.h:275
virtual void wakeup(Listable &item, queue_type::user_type user, bool prio, size_t q) noexcept
Definition sync.h:354
Listable * unblockFirst(size_t q=0, bool prio=false) noexcept
Definition sync.h:329
bool unblock(Fiber &f, size_t q=0, bool prio=false) noexcept
Unblock the specific fiber.
Definition sync.h:319
SynchronizerBase(cow_string &&name)
Definition sync.h:280
bool unblockAll(size_t q=0, bool prio=false) noexcept
Definition sync.h:340
bool blockFor(TimeInterval const &timeout, Timestamp const &now=Timestamp::now(), size_t q=0)
Block, with timeout.
Definition sync.h:429
virtual ~SynchronizerBase() noexcept override
Definition sync.h:286
bool blockUntil(Timestamp const &timeout, Timestamp const &now=Timestamp::now(), size_t q=0)
Block, with timeout.
Definition sync.h:415
Synchronizer(cow_string &&name)
Definition sync.h:477
base::queue_type queue_type
Definition sync.h:489
virtual queue_type & queue(size_t q) final
Definition sync.h:491
SynchronizerBase base
Definition sync.h:468
Synchronizer()=default
virtual ~Synchronizer() noexcept override
Definition sync.h:482
Convenient wrapper around struct timespec that contains a time interval.
Definition time.h:55
constexpr bool isNegative() const noexcept
Definition time.h:241
constexpr bool isNull() const noexcept
Definition time.h:251
virtual bool poll(Timestamp const &now=Timestamp::now()) noexcept override
Definition waiter.h:81
Timestamp const & timeout() const noexcept
Definition waiter.h:76
Convenient wrapper around struct timespec that contains an absolute timestamp.
Definition time.h:568
static Timestamp now()
Definition time.h:595
static constexpr Timestamp null() noexcept
Definition time.h:715
friend cow_string str(UniqueIDBase const &)
Keeps track of a process-wide unique ID within the type T.
Definition util.h:860
Fiber & fiber() const noexcept
Definition waiter.h:35
void scheduleTask(TimedWaitable &w)
Definition waiter.cpp:59
void unscheduleTask(TimedWaitable &w)
Definition waiter.cpp:71
The class that manages the fibers within this thread.
Definition worker.h:35
void release(Fiber &fiber) noexcept
Definition worker.h:161
Waiter & waiter() noexcept
Definition worker.h:99
Fiber * currentFiber() const noexcept
Definition worker.h:94
void add(Fiber *fiber, bool front=false) noexcept
Definition worker.h:104
bool schedule(Fiber *preferFiber=nullptr, Timestamp const &now=Timestamp::now())
Definition worker.h:175
Copy-on-write string.
Definition util.h:324
int zth_cond_broadcast(zth_cond_t *cond) noexcept
Signals all fibers waiting for the condition.
Definition sync.h:1799
int zth_mailbox_can_take(zth_mailbox_t *mailbox) noexcept
Checks if a mailbox contains data to take.
Definition sync.h:2048
int zth_future_valid(zth_future_t *future) noexcept
Checks if a future was already set.
Definition sync.h:1871
int zth_mutex_trylock(zth_mutex_t *mutex) noexcept
Try to lock a mutex.
Definition sync.h:1602
int zth_gate_pass(zth_gate_t *gate) noexcept
Passes a gate.
Definition sync.h:1977
int zth_mailbox_init(zth_mailbox_t *mailbox) noexcept
Initializes a mailbox.
Definition sync.h:2010
int zth_mutex_init(zth_mutex_t *mutex) noexcept
Initializes a mutex.
Definition sync.h:1550
int zth_cond_signal(zth_cond_t *cond) noexcept
Signals one fiber waiting for the condition.
Definition sync.h:1785
int zth_gate_init(zth_gate_t *gate, size_t count) noexcept
Initializes a gate.
Definition sync.h:1939
int zth_cond_wait(zth_cond_t *cond) noexcept
Wait for a condition.
Definition sync.h:1813
int zth_cond_destroy(zth_cond_t *cond) noexcept
Destroys a condition.
Definition sync.h:1767
int zth_future_get(zth_future_t *__restrict__ future, uintptr_t *__restrict__ value) noexcept
Wait for and return a future's value.
Definition sync.h:1903
int zth_gate_wait(zth_gate_t *gate) noexcept
Wait for a gate.
Definition sync.h:1990
int zth_cond_init(zth_cond_t *cond) noexcept
Initializes a condition.
Definition sync.h:1747
int zth_sem_post(zth_sem_t *sem) noexcept
Increments a semaphore.
Definition sync.h:1693
int zth_mutex_lock(zth_mutex_t *mutex) noexcept
Locks a mutex.
Definition sync.h:1588
int zth_mutex_destroy(zth_mutex_t *mutex) noexcept
Destroys a mutex.
Definition sync.h:1570
int zth_mailbox_take(zth_mailbox_t *__restrict__ mailbox, uintptr_t *__restrict__ value) noexcept
Wait for and return a mailbox's value.
Definition sync.h:2091
int zth_future_destroy(zth_future_t *future) noexcept
Destroys a future.
Definition sync.h:1853
int zth_future_set(zth_future_t *future, uintptr_t value) noexcept
Sets a future and signals all waiting fibers.
Definition sync.h:1884
int zth_sem_init(zth_sem_t *sem, size_t value) noexcept
Initializes a semaphore.
Definition sync.h:1633
int zth_mailbox_can_put(zth_mailbox_t *mailbox) noexcept
Checks if a mailbox is empty and can accept data.
Definition sync.h:2061
int zth_sem_destroy(zth_sem_t *sem) noexcept
Destroys a semaphore.
Definition sync.h:1656
int zth_sem_trywait(zth_sem_t *sem) noexcept
Try to decrement a semaphore.
Definition sync.h:1725
int zth_future_wait(zth_future_t *future) noexcept
Wait for a future.
Definition sync.h:1917
int zth_gate_destroy(zth_gate_t *gate) noexcept
Destroys a gate.
Definition sync.h:1959
int zth_sem_getvalue(zth_sem_t *__restrict__ sem, size_t *__restrict__ value) noexcept
Returns the value of a semaphore.
Definition sync.h:1675
int zth_mailbox_put(zth_mailbox_t *mailbox, uintptr_t value) noexcept
Puts a value into the mailbox.
Definition sync.h:2075
int zth_future_init(zth_future_t *future) noexcept
Initializes a future.
Definition sync.h:1833
int zth_mailbox_destroy(zth_mailbox_t *mailbox) noexcept
Destroys a mailbox.
Definition sync.h:2030
int zth_mutex_unlock(zth_mutex_t *mutex) noexcept
Unlock a mutex.
Definition sync.h:1615
int zth_sem_wait(zth_sem_t *sem) noexcept
Decrements (or wait for) a semaphore.
Definition sync.h:1711
Worker & currentWorker() noexcept
Return the (thread-local) singleton Worker instance.
Definition worker.h:407
void yield(Fiber *preferFiber=nullptr, bool alwaysYield=false, Timestamp const &now=Timestamp::now())
Allow a context switch.
Definition worker.h:454
Fiber & currentFiber() noexcept
Return the currently executing fiber.
Definition worker.h:417
#define zth_dbg(group, fmt, a...)
Debug printf()-like function.
Definition util.h:194
std::basic_string< char, std::char_traits< char >, Config::Allocator< char >::type > string
std::string type using Config::Allocator::type.
Definition util.h:315
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition allocator.h:159
#define constexpr14
Definition macros.h:208
#define zth_throw(...)
Definition macros.h:365
#define is_default
Definition macros.h:212
#define LREF_QUALIFIED
Definition macros.h:215
#define ZTH_INLINE
Definition macros.h:129
#define UNUSED_PAR(name)
Definition macros.h:78
STL namespace.
The configuration of Zth.
Definition zth_config.h:26
Base exception class for Zth exceptions.
Definition exception.h:16
Exception thrown when an operation cannot be performed as there is no fiber context.
Definition exception.h:21
void * p
Definition sync.h:1739
void * p
Definition sync.h:1823
void * p
Definition sync.h:1927
void * p
Definition sync.h:2000
void * p
Definition sync.h:1542
void * p
Definition sync.h:1625
zth::Future< uintptr_t > zth_future_t_type
Definition sync.h:1826
zth::Mailbox< uintptr_t > zth_mailbox_t_type
Definition sync.h:2003
#define EOVERFLOW
Definition sync.h:1685
#define ZTH_STRUCTURED_BINDING_FORWARDING_NS(Class)
Definition util.h:1639
#define zth_assert(expr)
assert(), but better integrated in Zth.
Definition util.h:217
#define likely(expr)
Marks the given expression to likely be evaluated to true.
Definition util.h:45
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.
Definition util.h:60