32 Key(uintptr_t transaction = 0,
size_t generation = 0,
size_t subscription = 0)
33 : transaction(transaction), generation(generation), subscription(subscription) {}
35 uintptr_t transaction;
39 bool operator==(
const Key& other)
const {
40 return transaction == other.transaction && generation == other.generation &&
41 subscription == other.subscription;
45 using Callback = void (*)(uintptr_t, ssize_t);
46 using AfterDelivery = void (*)(
void*);
47 using OnDestroy = void (*)(
void*);
59 Record(
const Key& key, Callback callback, uintptr_t parameter, ssize_t result,
60 AfterDelivery afterDelivery,
void* afterDeliveryContext, OnDestroy onDestroy,
64 m_Parameter(parameter),
66 m_AfterDelivery(afterDelivery),
67 m_AfterDeliveryContext(afterDeliveryContext),
68 m_OnDestroy(onDestroy),
69 m_DestroyContext(destroyContext),
73 m_CompletionWaiters(),
78 m_OnDestroy(m_DestroyContext);
86 if ((m_References -= 1) == 0)
90 void waitForCompletion() {
92 auto guard = m_CompletionWaiters.acquire();
101 auto guard = m_CompletionWaiters.acquire();
108 uintptr_t m_Parameter;
110 AfterDelivery m_AfterDelivery;
111 void* m_AfterDeliveryContext;
112 OnDestroy m_OnDestroy;
113 void* m_DestroyContext;
131 MUST_USE_RESULT Record* create(
const Key& key, Callback callback, uintptr_t parameter,
132 ssize_t result, AfterDelivery afterDelivery =
nullptr,
133 void* afterDeliveryContext =
nullptr,
134 OnDestroy onDestroy =
nullptr,
void* destroyContext =
nullptr) {
135 return new Record(key, callback, parameter, result, afterDelivery, afterDeliveryContext,
136 onDestroy, destroyContext);
139 size_t nextGeneration() {
140 size_t generation = m_NextGeneration += 1;
142 generation = m_NextGeneration += 1;
150 assert(findLocked((*it)->m_Key) ==
nullptr);
151 m_Records.pushBack(*it);
161 if (record->
m_State == Record::State::Pending) {
162 record->
m_State = Record::State::Running;
163 record->m_Runner = currentRunner();
165 }
else if (record->
m_State == Record::State::Running) {
166 wait = record->m_Runner != currentRunner();
173 record->waitForCompletion();
190 record = findLocked(key);
195 if (record->
m_State == Record::State::Pending) {
196 record->
m_State = Record::State::Running;
197 record->m_Runner = currentRunner();
199 }
else if (record->
m_State == Record::State::Running) {
200 self = record->m_Runner == currentRunner();
207 record->waitForCompletion();
223 bool runningTarget =
false;
224 const bool callerIsCallback = inCallbackContext();
227 bool suppressed =
false;
233 if (candidate->m_Key.transaction != transaction ||
234 candidate->m_Key.subscription != subscription) {
238 if (candidate->
m_State == Record::State::Running &&
239 (callerIsCallback || candidate->m_Runner == currentRunner())) {
240 runningTarget =
true;
246 if (record->
m_State == Record::State::Pending) {
248 record->
m_State = Record::State::Complete;
249 record->m_Runner =
nullptr;
251 }
else if (record->
m_State == Record::State::Running) {
259 return !runningTarget;
264 record->waitForCompletion();
285 if (record->
m_State == Record::State::Running && record->m_Runner == currentRunner()) {
302 bool contains(
const Key& key) {
304 return findLocked(key) !=
nullptr;
307 size_t activeCount() {
309 return m_Records.count();
313 return activeCount() == 0;
318 return inCallbackContext();
331 m_Active.next = callbackContexts();
332 callbackContexts() = &m_Active;
338 while (*link && *link != &m_Active)
339 link = &((*link)->next);
340 assert(*link == &m_Active);
342 *link = m_Active.next;
349 static Mutex& callbackContextLock() {
354 static ActiveCallback*& callbackContexts() {
355 static ActiveCallback* contexts =
nullptr;
359 static bool inCallbackContext() {
360 const void* runner = currentRunner();
362 for (ActiveCallback* active = callbackContexts(); active; active = active->next) {
363 if (active->runner == runner)
369 static void* currentRunner() {
371 auto* thread = information.getCurrentThread();
372 return thread ?
static_cast<void*
>(thread) : static_cast<void*>(&information);
375 Record* findLocked(
const Key& key) {
377 if ((*it)->m_Key == key)
383 void finishRecord(Record* record) {
386 bool removed =
false;
395 record->m_State = Record::State::Complete;
396 record->m_Runner =
nullptr;
401 void runRecord(Record* record) {
403 CallbackContext callbackContext;
405 if (record->m_Callback)
406 record->m_Callback(record->m_Parameter, record->m_Result);
407 if (record->m_AfterDelivery)
408 record->m_AfterDelivery(record->m_AfterDeliveryContext);
410 finishRecord(record);
417 NOT_COPYABLE_OR_ASSIGNABLE(CallbackDeliveryQueue);