# HG changeset patch # User Paul Boddie # Date 1626388735 -7200 # Node ID b0f34fc8d4d8192d634a803db7bec8567ce4e661 # Parent 404caa4bc10de0dba561e22da34d8cd2fdc8ed42 Introduced locking and support for incremental endpoint allocation. diff -r 404caa4bc10d -r b0f34fc8d4d8 libfsserver/include/fsserver/notification.h --- a/libfsserver/include/fsserver/notification.h Tue Jul 13 23:18:37 2021 +0200 +++ b/libfsserver/include/fsserver/notification.h Fri Jul 16 00:38:55 2021 +0200 @@ -21,6 +21,7 @@ #pragma once +#include #include #include @@ -38,7 +39,7 @@ { public: NotifierSet notifiers; - notify_flags_t flags, deferred; + notify_flags_t flags = 0, deferred = 0; }; typedef std::vector NotificationEndpointList; @@ -51,6 +52,8 @@ class NotificationSupport { protected: + std::mutex _lock; + /* Endpoint count. */ unsigned int _min_endpoints; @@ -59,8 +62,16 @@ NotificationEndpointList _endpoints; + /* Deferred notifications for new endpoints. */ + + notify_flags_t _deferred = 0; + virtual void release_notifiers(); + virtual void _notify(unsigned int endpoint, notify_flags_t flags); + + virtual void _subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags); + public: explicit NotificationSupport(unsigned int endpoints=0); @@ -68,6 +79,8 @@ virtual void notify_others(unsigned int endpoint, notify_flags_t flags); + virtual unsigned int subscribe(l4_cap_idx_t notifier, notify_flags_t flags); + virtual void subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags); virtual void unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier); diff -r 404caa4bc10d -r b0f34fc8d4d8 libfsserver/lib/generic/notification.cc --- a/libfsserver/lib/generic/notification.cc Tue Jul 13 23:18:37 2021 +0200 +++ b/libfsserver/lib/generic/notification.cc Fri Jul 16 00:38:55 2021 +0200 @@ -34,13 +34,51 @@ _endpoints.resize(_min_endpoints); } -/* Subscribe to an endpoint's notifications using a notification endpoint. */ +/* Subscribe to notifications using a notification object, returning the + endpoint number. */ + +unsigned int NotificationSupport::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) +{ + std::lock_guard guard(_lock); + + unsigned int endpoint = _endpoints.size(); + + _endpoints.resize(endpoint + 1); + + /* Propagate deferred flags for new endpoints. */ + + if (_deferred) + _endpoints[endpoint].deferred = _deferred; + + _subscribe(endpoint, notifier, flags); + + return endpoint; +} + +/* Subscribe to a specific endpoint's notifications using a notification + object. */ void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) { + std::lock_guard guard(_lock); + if (endpoint >= _endpoints.size()) + { _endpoints.resize(endpoint + 1); + /* Propagate deferred flags for new endpoints. */ + + if (_deferred) + _endpoints[endpoint].deferred = _deferred; + } + + _subscribe(endpoint, notifier, flags); +} + +/* Common subscription functionality. */ + +void NotificationSupport::_subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) +{ NotificationEndpoint &ep = _endpoints[endpoint]; ep.notifiers.insert(notifier); @@ -50,7 +88,7 @@ if (ep.deferred) { - notify(endpoint, ep.deferred); + _notify(endpoint, ep.deferred); ep.deferred = 0; } } @@ -59,6 +97,8 @@ void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) { + std::lock_guard guard(_lock); + if (endpoint >= _endpoints.size()) return; @@ -82,6 +122,13 @@ void NotificationSupport::notify(unsigned int endpoint, notify_flags_t flags) { + std::lock_guard guard(_lock); + + _notify(endpoint, flags); +} + +void NotificationSupport::_notify(unsigned int endpoint, notify_flags_t flags) +{ if (endpoint >= _endpoints.size()) return; @@ -112,15 +159,21 @@ void NotificationSupport::notify_others(unsigned int endpoint, notify_flags_t flags) { + std::lock_guard guard(_lock); + for (unsigned int i = 0; i < _endpoints.size(); i++) if (i != endpoint) - notify(i, flags); + _notify(i, flags); + + _deferred |= flags; } /* Release notifiers for each endpoint. */ void NotificationSupport::release_notifiers() { + std::lock_guard guard(_lock); + for (unsigned int endpoint = 0; endpoint < _endpoints.size(); endpoint++) { NotificationEndpoint &ep = _endpoints[endpoint];