Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
CallbackRegistry.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include <algorithm>
5
12#include "Stroika/Foundation/Execution/Throw.h"
13
15
16 /*
17 ********************************************************************************
18 ************************** Execution::CallbackRegistry *************************
19 ********************************************************************************
20 */
21 template <typename... ARGS>
22 inline CallbackRegistry<void (ARGS...)>::Entry_::Entry_ (ID id, const Callback& callback)
23 : fID{id}
24 , fCallback{callback}
25 {
26 }
27 template <typename... ARGS>
28 inline CallbackRegistry<void (ARGS...)>::~CallbackRegistry ()
29 {
31 [[maybe_unused]] lock_guard critSec{fMutex_};
32 for ([[maybe_unused]] const shared_ptr<Entry_>& e : fEntries_) {
33 Require (e->fRunningOn.empty ()); // else a callback is running, on a registry going away
34 }
35 }
36 }
37 template <typename... ARGS>
38 auto CallbackRegistry<void (ARGS...)>::Add (const Callback& callback) -> ID
39 {
40 Require (callback != nullptr);
41 auto e = Memory::MakeSharedPtr<Entry_> (ID::New (), callback);
42
43 [[maybe_unused]] lock_guard critSec{fMutex_};
44 fEntries_.push_back (e);
45 return e->fID;
46 }
47 template <typename... ARGS>
48 void CallbackRegistry<void (ARGS...)>::Remove (ID id) noexcept
49 {
50 unique_lock critSec{fMutex_};
51 auto i = find_if (fEntries_.begin (), fEntries_.end (), [&] (const shared_ptr<Entry_>& e) { return e->fID == id; });
52 if (i == fEntries_.end ()) {
53 return; // not added (or already removed)
54 }
55 shared_ptr<Entry_> e = *i;
56 fEntries_.erase (i);
57 e->fRemoved = true; // so a Call that copied the list before this calls it no more
58 // and wait for a call of it running on another thread - not this one's: that is the callback removing itself
59 const thread::id me = this_thread::get_id ();
60 fCallEnded_.wait (critSec,
61 [&] () { return all_of (e->fRunningOn.begin (), e->fRunningOn.end (), [&] (thread::id t) { return t == me; }); });
62 }
63 template <typename... ARGS>
64 void CallbackRegistry<void (ARGS...)>::RemoveAll () noexcept
65 {
66 unique_lock critSec{fMutex_};
67 vector<shared_ptr<Entry_>> removed;
68 removed.swap (fEntries_);
69 for (const shared_ptr<Entry_>& e : removed) {
70 e->fRemoved = true;
71 }
72 // and wait for any of them running on another thread
73 const thread::id me = this_thread::get_id ();
74 fCallEnded_.wait (critSec, [&] () {
75 return all_of (removed.begin (), removed.end (), [&] (const shared_ptr<Entry_>& e) {
76 return all_of (e->fRunningOn.begin (), e->fRunningOn.end (), [&] (thread::id t) { return t == me; });
77 });
78 });
79 }
80 template <typename... ARGS>
81 void CallbackRegistry<void (ARGS...)>::Call (ARGS... args)
82 {
83 using namespace Characters::Literals;
84 vector<shared_ptr<Entry_>> entries;
85 {
86 [[maybe_unused]] lock_guard critSec{fMutex_};
87 entries = fEntries_; // a copy, to call holding no lock: a callback may add or remove callbacks
88 }
89 const thread::id me = this_thread::get_id ();
90 for (const shared_ptr<Entry_>& e : entries) {
91 {
92 [[maybe_unused]] lock_guard critSec{fMutex_};
93 if (e->fRemoved) {
94 continue; // removed since the copy was made
95 }
96 e->fRunningOn.push_back (me);
97 }
98 [[maybe_unused]] auto&& cleanup = Finally ([&] () noexcept {
99 {
100 [[maybe_unused]] lock_guard critSec{fMutex_};
101 e->fRunningOn.erase (find (e->fRunningOn.begin (), e->fRunningOn.end (), me));
102 }
103 fCallEnded_.notify_all (); // for a Remove waiting for it
104 });
105 try {
106 e->fCallback (args...);
107 }
108 catch (const Thread::AbortException&) {
109 ReThrow ();
110 }
111 catch (...) {
112 DbgTrace ("CallbackRegistry: ignoring exception from a callback: {}"_f, current_exception ());
113 }
114 }
115 }
116
117}
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:49
#define DbgTrace
Definition Trace.h:327
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
Definition Finally.inl:31