# HG changeset patch # User Paul Boddie # Date 1680543335 -7200 # Node ID b4b80ed8624b55fb82596e85910ff6bd7579f4fb # Parent 8781ca0538a8a2b3dbd303be0a1eeb5fc2065ebc Simplified the notifier architecture, attempting to address concurrency issues. diff -r 8781ca0538a8 -r b4b80ed8624b libnotifier/include/notifier/notifier.h --- a/libnotifier/include/notifier/notifier.h Mon Apr 03 16:41:11 2023 +0200 +++ b/libnotifier/include/notifier/notifier.h Mon Apr 03 19:35:35 2023 +0200 @@ -65,6 +65,8 @@ virtual long unsubscribe(notifiable_t *object); + virtual void update(notifiable_t *object); + virtual long wait(notifiable_t **object); virtual long wait_object(notifiable_t *object); @@ -99,10 +101,6 @@ ObjectNotifiers _notifiers; notifiable_t *_object; - /* Pending notification status. */ - - bool _pending = false; - /* Utility methods. */ virtual void _notify(); @@ -139,8 +137,6 @@ virtual long add(ObjectNotifier *notifier, notify_flags_t flags); virtual long remove(ObjectNotifier *notifier); - - virtual long wait(); }; diff -r 8781ca0538a8 -r b4b80ed8624b libnotifier/lib/src/notifier.cc --- a/libnotifier/lib/src/notifier.cc Mon Apr 03 16:41:11 2023 +0200 +++ b/libnotifier/lib/src/notifier.cc Mon Apr 03 19:35:35 2023 +0200 @@ -98,6 +98,7 @@ std::lock_guard guard(_monitored_lock); _monitored.erase(object); + object->handler = NULL; } /* Subscribe to notification events on an object. */ @@ -148,6 +149,7 @@ NotifierResource *resource = reinterpret_cast(object->handler); _monitored.erase(object); + object->handler = NULL; return resource->remove(this); } @@ -157,7 +159,7 @@ { /* Enter critical section to access the queue. */ - std::lock_guard guard(_affected_lock); + std::unique_lock guard(_affected_lock); /* Ensure that a queue entry exists for the object. */ @@ -169,9 +171,19 @@ _affected.insert(object); } - /* Notify any waiting caller that at least one notification is available. */ + /* Notify all waiting callers that at least one notification is available. */ + + _condition.notify_all(); +} + +/* Update the notifiable object when being notified. */ - _condition.notify_one(); +void ObjectNotifier::update(notifiable_t *object) +{ + object->notifications = object->pending_notifications; + object->values = object->pending_values; + + object->pending_notifications = 0; } /* Wait for notification events on objects, returning each object that has a @@ -200,6 +212,9 @@ _condition.wait(guard); } + /* Synchronise the notification flags and values. */ + + update(*object); return L4_EOK; } @@ -207,10 +222,43 @@ long ObjectNotifier::wait_object(notifiable_t *object) { - if (object->handler == NULL) - return -L4_EINVAL; + /* Enter critical section to access the queue. */ + + std::unique_lock guard(_affected_lock); + + while (1) + { + /* With pending notifications, find any for the specified object. */ + + NotifiableObjects::iterator it = _affected.find(object); + + if (it != _affected.end()) + { + /* Remove the object from the queue. */ + + NotifiableObjectQueue::iterator itq; - reinterpret_cast(object->handler)->wait(); + for (itq = _queued.begin(); itq != _queued.end(); itq++) + { + if (*itq == object) + { + _queued.erase(itq); + break; + } + } + + _affected.erase(it); + break; + } + + /* Otherwise, wait for notifications. */ + + _condition.wait(guard); + } + + /* Synchronise the notification flags and values. */ + + update(object); return L4_EOK; } @@ -227,7 +275,6 @@ void NotifierResource::close() { _release(); - _object->handler = NULL; } /* Object-specific resource methods. */ @@ -284,8 +331,8 @@ { /* Update the notifiable object. */ - _object->notifications |= flags; - _object->values = values; + _object->pending_notifications |= flags; + _object->pending_values = values; _notify(); return L4_EOK; @@ -297,14 +344,6 @@ std::lock_guard guard(_lock); - /* Record a pending notification which persists if nothing is waiting. */ - - _pending = true; - - /* Notify any party waiting specifically on this object. */ - - _condition.notify_one(); - /* Register the notification with all notifier objects. */ ObjectNotifiers::iterator it; @@ -325,22 +364,5 @@ (*it)->release(_object); } -/* Wait for notification events on a specific object. */ - -long NotifierResource::wait() -{ - /* Enter critical section for the resource. */ - - std::unique_lock guard(_lock); - - /* Wait for the notification condition. */ - - if (!_pending) - _condition.wait(guard); - - _pending = false; - return L4_EOK; -} - /* vim: tabstop=2 expandtab shiftwidth=2 */ diff -r 8781ca0538a8 -r b4b80ed8624b libsystypes/include/systypes/base.h --- a/libsystypes/include/systypes/base.h Mon Apr 03 16:41:11 2023 +0200 +++ b/libsystypes/include/systypes/base.h Mon Apr 03 19:35:35 2023 +0200 @@ -76,7 +76,9 @@ { notifiable_base_t *base; /* access to the specific object */ notify_flags_t notifications; /* essential notifications */ + notify_flags_t pending_notifications; notify_values_t values; /* signal-specific values */ + notify_values_t pending_values; void *handler; /* associated notification handler */ } notifiable_t;