1.1 --- a/libfsclient/lib/src/file.cc Wed Mar 29 00:32:20 2023 +0200
1.2 +++ b/libfsclient/lib/src/file.cc Mon Apr 03 00:35:34 2023 +0200
1.3 @@ -96,6 +96,7 @@
1.4
1.5 file->notifiable.notifications = 0;
1.6 file->notifiable.base = (notifiable_base_t *) file;
1.7 + file->notifiable.handler = NULL;
1.8 }
1.9
1.10
1.11 @@ -634,7 +635,6 @@
1.12
1.13 void file_notify_close(file_notifier_t *notifier)
1.14 {
1.15 - notifier->obj->stop();
1.16 delete notifier->obj;
1.17 delete notifier;
1.18 }
1.19 @@ -677,8 +677,7 @@
1.20
1.21 long file_notify_wait_file(file_t *file, file_notifier_t *notifier)
1.22 {
1.23 - SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj);
1.24 - long err = specific_notifier->wait_object(file_notifiable(file));
1.25 + long err = notifier->obj->wait_object(file_notifiable(file));
1.26
1.27 /* Unsubscribe if a closure notification has been received. */
1.28
1.29 @@ -692,9 +691,8 @@
1.30
1.31 long file_notify_wait_files(file_t **file, file_notifier_t *notifier)
1.32 {
1.33 - GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj);
1.34 notifiable_t *notifiable;
1.35 - long err = general_notifier->wait(¬ifiable);
1.36 + long err = notifier->obj->wait(¬ifiable);
1.37
1.38 *file = (file_t *) notifiable->base;
1.39
2.1 --- a/libfsclient/lib/src/process.cc Wed Mar 29 00:32:20 2023 +0200
2.2 +++ b/libfsclient/lib/src/process.cc Mon Apr 03 00:35:34 2023 +0200
2.3 @@ -65,6 +65,12 @@
2.4 void process_init(process_t *process)
2.5 {
2.6 process->ref = L4_INVALID_CAP;
2.7 +
2.8 + /* Initialise the notifiable section of the structure. */
2.9 +
2.10 + process->notifiable.notifications = 0;
2.11 + process->notifiable.base = (notifiable_base_t *) process;
2.12 + process->notifiable.handler = NULL;
2.13 }
2.14
2.15 /* Start a process using the given arguments.
2.16 @@ -152,7 +158,6 @@
2.17
2.18 void process_notify_close(process_notifier_t *notifier)
2.19 {
2.20 - notifier->obj->stop();
2.21 delete notifier->obj;
2.22 delete notifier;
2.23 }
2.24 @@ -195,8 +200,7 @@
2.25
2.26 long process_notify_wait_process(process_t *process, process_notifier_t *notifier)
2.27 {
2.28 - SpecificObjectNotifier *specific_notifier = dynamic_cast<SpecificObjectNotifier *>(notifier->obj);
2.29 - long err = specific_notifier->wait_object(process_notifiable(process));
2.30 + long err = notifier->obj->wait_object(process_notifiable(process));
2.31
2.32 /* Unsubscribe if a termination notification has been received. */
2.33
2.34 @@ -214,9 +218,8 @@
2.35
2.36 long process_notify_wait_processes(process_t **process, process_notifier_t *notifier)
2.37 {
2.38 - GeneralObjectNotifier *general_notifier = dynamic_cast<GeneralObjectNotifier *>(notifier->obj);
2.39 notifiable_t *notifiable;
2.40 - long err = general_notifier->wait(¬ifiable);
2.41 + long err = notifier->obj->wait(¬ifiable);
2.42
2.43 *process = (process_t *) notifiable->base;
2.44
3.1 --- a/libnotifier/include/notifier/notifier.h Wed Mar 29 00:32:20 2023 +0200
3.2 +++ b/libnotifier/include/notifier/notifier.h Mon Apr 03 00:35:34 2023 +0200
3.3 @@ -23,8 +23,8 @@
3.4
3.5 #include <condition_variable>
3.6 #include <list>
3.7 -#include <map>
3.8 #include <mutex>
3.9 +#include <set>
3.10 #include <vector>
3.11
3.12 #include <resource/resource.h>
3.13 @@ -34,36 +34,10 @@
3.14
3.15
3.16
3.17 -/* Object-specific notification details. */
3.18 -
3.19 -class ObjectNotificationState
3.20 -{
3.21 -public:
3.22 - /* Synchronisation primitives for state access and notification. */
3.23 -
3.24 - std::mutex lock;
3.25 - std::condition_variable condition;
3.26 -
3.27 - /* Pending notifications for monitored objects. */
3.28 -
3.29 - notify_flags_t pending_notifications = 0;
3.30 - notify_values_t pending_values = NOTIFY_VALUES_NULL;
3.31 -
3.32 - /* Endpoints associated with monitored objects. */
3.33 -
3.34 - l4_cap_idx_t endpoint = L4_INVALID_CAP;
3.35 -
3.36 - bool is_null() { return l4_is_invalid_cap(endpoint); }
3.37 -};
3.38 -
3.39 -
3.40 -
3.41 /* Collection types. */
3.42
3.43 -typedef std::map<notifiable_t *, ObjectNotificationState> ObjectNotificationStates;
3.44 -typedef std::map<notifiable_t *, std::mutex> ObjectStateLocks;
3.45 -
3.46 -typedef std::vector<ipc_server_config_type *> ServerConfigs;
3.47 +typedef std::list<notifiable_t *> NotifiableObjectQueue;
3.48 +typedef std::set<notifiable_t *> NotifiableObjects;
3.49
3.50
3.51
3.52 @@ -72,102 +46,41 @@
3.53 class ObjectNotifier
3.54 {
3.55 protected:
3.56 - /* General state access locking. */
3.57 -
3.58 - std::mutex _state_lock;
3.59 -
3.60 - /* Object-specific state locking. */
3.61 + /* Locking for the affected queue and monitored object registry. */
3.62
3.63 - ObjectStateLocks _object_locks;
3.64 -
3.65 - /* Notification state. */
3.66 -
3.67 - ObjectNotificationStates _state;
3.68 + std::mutex _affected_lock, _monitored_lock;
3.69 + std::condition_variable _condition;
3.70
3.71 - /* Notifier resource details. */
3.72 -
3.73 - ServerConfigs _configs;
3.74 - bool _started = false;
3.75 - l4_cap_idx_t _irq = L4_INVALID_CAP;
3.76 + /* Objects affected by notifications. */
3.77
3.78 - /* Convenience method to access object state. */
3.79 -
3.80 - virtual ObjectNotificationState &object_state(notifiable_t *object, bool create);
3.81 -
3.82 - /* Helper methods. */
3.83 -
3.84 - virtual bool _transfer(ObjectNotificationState &state, notifiable_t *object);
3.85 + NotifiableObjectQueue _queued;
3.86 + NotifiableObjects _affected, _monitored;
3.87
3.88 public:
3.89 virtual ~ObjectNotifier();
3.90
3.91 /* Local operations. */
3.92
3.93 - virtual long start();
3.94 -
3.95 - virtual void stop();
3.96 -
3.97 virtual long subscribe(notifiable_t *object, notify_flags_t flags);
3.98
3.99 virtual long unsubscribe(notifiable_t *object);
3.100
3.101 - virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
3.102 + virtual long wait(notifiable_t **object);
3.103 +
3.104 + virtual long wait_object(notifiable_t *object);
3.105
3.106 /* Helper methods. */
3.107
3.108 - virtual void notify(notifiable_t *object, notify_flags_t flags,
3.109 - notify_values_t values) = 0;
3.110 + virtual void notify(notifiable_t *object);
3.111 +
3.112 + virtual void release(notifiable_t *object);
3.113 };
3.114
3.115
3.116
3.117 -/* An object monitoring notifications for a collection of different objects. */
3.118 -
3.119 -class GeneralObjectNotifier : public ObjectNotifier
3.120 -{
3.121 -protected:
3.122 - /* Locking to protect pending notification members and to coordinate access
3.123 - to notifications. */
3.124 -
3.125 - std::mutex _general_lock;
3.126 -
3.127 - /* General lock synchronisation. */
3.128 -
3.129 - std::condition_variable _general_condition;
3.130 -
3.131 - /* Objects affected by notifications. */
3.132 -
3.133 - std::list<notifiable_t *> _affected;
3.134 -
3.135 - /* Helper methods. */
3.136 -
3.137 - virtual bool _retrieve(notifiable_t **object);
3.138 -
3.139 - virtual bool _retrieve_for_object(notifiable_t *object);
3.140 +/* Collection types. */
3.141
3.142 -public:
3.143 - virtual long wait(notifiable_t **object);
3.144 -
3.145 - /* Helper methods. */
3.146 -
3.147 - virtual void notify(notifiable_t *object, notify_flags_t flags,
3.148 - notify_values_t values);
3.149 -};
3.150 -
3.151 -
3.152 -
3.153 -/* An object monitoring notifications for specific objects. */
3.154 -
3.155 -class SpecificObjectNotifier : public ObjectNotifier
3.156 -{
3.157 -public:
3.158 - virtual long wait_object(notifiable_t *object);
3.159 -
3.160 - /* Helper methods. */
3.161 -
3.162 - virtual void notify(notifiable_t *object, notify_flags_t flags,
3.163 - notify_values_t values);
3.164 -};
3.165 +typedef std::set<ObjectNotifier *> ObjectNotifiers;
3.166
3.167
3.168
3.169 @@ -176,19 +89,39 @@
3.170 class NotifierResource : public Notifier, public Resource
3.171 {
3.172 protected:
3.173 - ObjectNotifier *_notifier;
3.174 + /* Locking for the resource. */
3.175 +
3.176 + std::mutex _lock;
3.177 + std::condition_variable _condition;
3.178 +
3.179 + /* Notifiers and the monitored object. */
3.180 +
3.181 + ObjectNotifiers _notifiers;
3.182 notifiable_t *_object;
3.183
3.184 + /* Pending notification status. */
3.185 +
3.186 + bool _pending = false;
3.187 +
3.188 + /* Utility methods. */
3.189 +
3.190 + virtual void _notify();
3.191 +
3.192 + virtual void _release();
3.193 +
3.194 public:
3.195 - explicit NotifierResource(ObjectNotifier *notifier, notifiable_t *object)
3.196 - : _notifier(notifier), _object(object)
3.197 + l4_cap_idx_t endpoint = L4_INVALID_CAP;
3.198 +
3.199 + explicit NotifierResource(notifiable_t *object)
3.200 + : _object(object)
3.201 {
3.202 }
3.203
3.204 - explicit NotifierResource()
3.205 - : _notifier(NULL), _object(NULL)
3.206 - {
3.207 - }
3.208 + virtual ~NotifierResource();
3.209 +
3.210 + /* Resource methods. */
3.211 +
3.212 + virtual void close();
3.213
3.214 /* Server details. */
3.215
3.216 @@ -200,14 +133,22 @@
3.217 /* Notifier methods. */
3.218
3.219 virtual long notify(notify_flags_t flags, notify_values_t values);
3.220 +
3.221 + /* Local operations. */
3.222 +
3.223 + virtual long add(ObjectNotifier *notifier, notify_flags_t flags);
3.224 +
3.225 + virtual long remove(ObjectNotifier *notifier);
3.226 +
3.227 + virtual long wait();
3.228 };
3.229
3.230
3.231
3.232 /* Helper functions. */
3.233
3.234 -SpecificObjectNotifier *notifier_get_task_notifier();
3.235 +ObjectNotifier *notifier_get_task_notifier();
3.236
3.237 -GeneralObjectNotifier *notifier_get_local_notifier();
3.238 +ObjectNotifier *notifier_get_local_notifier();
3.239
3.240 // vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libnotifier/lib/src/notifier.cc Wed Mar 29 00:32:20 2023 +0200
4.2 +++ b/libnotifier/lib/src/notifier.cc Mon Apr 03 00:35:34 2023 +0200
4.3 @@ -19,11 +19,6 @@
4.4 * Boston, MA 02110-1301, USA
4.5 */
4.6
4.7 -#include <map>
4.8 -#include <mutex>
4.9 -
4.10 -#include <l4/sys/irq.h>
4.11 -
4.12 #include <ipc/cap_alloc.h>
4.13 #include <ipc/server.h>
4.14 #include <resource/resource_server.h>
4.15 @@ -34,47 +29,35 @@
4.16
4.17
4.18
4.19 -/* Null notification state. */
4.20 -
4.21 -static ObjectNotificationState _null_state;
4.22 -
4.23 -
4.24 -
4.25 /* Lock protecting per-task notifier access. */
4.26
4.27 -static std::mutex _lock;
4.28 +static std::mutex _task_lock;
4.29
4.30 /* Per-task storage for specific waiting operations. */
4.31
4.32 -static SpecificObjectNotifier *_notifier = NULL;
4.33 +static ObjectNotifier *_notifier = NULL;
4.34
4.35
4.36
4.37 /* Return the per-task notifier for object-specific waiting operations. */
4.38
4.39 -SpecificObjectNotifier *notifier_get_task_notifier()
4.40 +ObjectNotifier *notifier_get_task_notifier()
4.41 {
4.42 - std::lock_guard<std::mutex> guard(_lock);
4.43 + std::lock_guard<std::mutex> guard(_task_lock);
4.44
4.45 /* Start any new notifier. */
4.46
4.47 if (_notifier == NULL)
4.48 - {
4.49 - _notifier = new SpecificObjectNotifier;
4.50 - _notifier->start();
4.51 - }
4.52 + _notifier = new ObjectNotifier;
4.53
4.54 return _notifier;
4.55 }
4.56
4.57 /* Return a local notifier for general object waiting operations. */
4.58
4.59 -GeneralObjectNotifier *notifier_get_local_notifier()
4.60 +ObjectNotifier *notifier_get_local_notifier()
4.61 {
4.62 - GeneralObjectNotifier *notifier = new GeneralObjectNotifier;
4.63 -
4.64 - notifier->start();
4.65 - return notifier;
4.66 + return new ObjectNotifier;
4.67 }
4.68
4.69
4.70 @@ -83,358 +66,170 @@
4.71
4.72 ObjectNotifier::~ObjectNotifier()
4.73 {
4.74 - stop();
4.75 + /* Remove this notifier from the individual notifier resources. */
4.76 +
4.77 + NotifiableObjects::iterator it;
4.78
4.79 - ServerConfigs::iterator it;
4.80 + for (it = _monitored.begin(); it != _monitored.end(); it++)
4.81 + {
4.82 + notifiable_t *object = *it;
4.83
4.84 - for (it = _configs.begin(); it != _configs.end(); it++)
4.85 - delete *it;
4.86 + if (object->handler != NULL)
4.87 + {
4.88 + NotifierResource *resource = reinterpret_cast<NotifierResource *>(object->handler);
4.89 + resource->remove(this);
4.90 + }
4.91 + }
4.92
4.93 - _configs.clear();
4.94 + _monitored.clear();
4.95
4.96 /* Handle deletion of the special task notifier. */
4.97
4.98 + std::lock_guard<std::mutex> guard(_task_lock);
4.99 +
4.100 if (this == _notifier)
4.101 _notifier = NULL;
4.102 }
4.103
4.104 -
4.105 -
4.106 -/* Start listening for notifications. */
4.107 -
4.108 -long ObjectNotifier::start()
4.109 -{
4.110 - if (_started)
4.111 - return L4_EOK;
4.112 -
4.113 - /* Create a new thread to serve a "null" resource. This resource is not used
4.114 - for notifications but merely for control purposes. */
4.115 -
4.116 - NotifierResource *notifier = new NotifierResource;
4.117 - ResourceServer server(notifier);
4.118 - long err = server.start_thread(true, false);
4.119 -
4.120 - if (err)
4.121 - return err;
4.122 -
4.123 - _configs.push_back(server.config());
4.124 - _started = true;
4.125 -
4.126 - /* Retain the IRQ created for the server for control purposes. */
4.127 -
4.128 - _irq = server.config()->irq;
4.129 -
4.130 - return L4_EOK;
4.131 -}
4.132 -
4.133 +/* Handle a deletion event for an object. */
4.134
4.135 -
4.136 -/* Stop the notifier. */
4.137 -
4.138 -void ObjectNotifier::stop()
4.139 +void ObjectNotifier::release(notifiable_t *object)
4.140 {
4.141 - if (l4_is_valid_cap(_irq))
4.142 - {
4.143 - l4_irq_trigger(_irq);
4.144 - _irq = L4_INVALID_CAP;
4.145 - }
4.146 -}
4.147 -
4.148 -
4.149 + std::lock_guard<std::mutex> guard(_monitored_lock);
4.150
4.151 -/* Return notification state for the given object or null state if no record
4.152 - existed for the object. */
4.153 -
4.154 -ObjectNotificationState &ObjectNotifier::object_state(notifiable_t *object, bool create)
4.155 -{
4.156 - ObjectNotificationStates::iterator it = _state.find(object);
4.157 -
4.158 - if (it == _state.end())
4.159 - {
4.160 - if (create)
4.161 - return _state[object];
4.162 - else
4.163 - return _null_state;
4.164 - }
4.165 -
4.166 - return it->second;
4.167 + _monitored.erase(object);
4.168 }
4.169
4.170 /* Subscribe to notification events on an object. */
4.171
4.172 long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
4.173 {
4.174 - /* Acquire the lock for state lookup. */
4.175 -
4.176 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.177 + std::lock_guard<std::mutex> guard(_monitored_lock);
4.178
4.179 - /* Obtain potentially new state for the object. */
4.180 + /* Ensure that a handler resource is available for object notifications. */
4.181
4.182 - ObjectNotificationState &state = object_state(object, true);
4.183 + NotifierResource *resource;
4.184
4.185 - if (state.is_null())
4.186 - {
4.187 - /* Serve the new object in the notifier thread. */
4.188 + if (object->handler != NULL)
4.189 + resource = reinterpret_cast<NotifierResource *>(object->handler);
4.190 +
4.191 + /* Create a resource if none is recorded. */
4.192
4.193 - NotifierResource *resource = new NotifierResource(this, object);
4.194 + else
4.195 + {
4.196 + resource = new NotifierResource(object);
4.197 ResourceServer server(resource);
4.198 - long err = server.start_in_thread(_configs.front()->thread);
4.199 + long err = server.start_thread(&resource->endpoint);
4.200
4.201 if (err)
4.202 return err;
4.203
4.204 - _configs.push_back(server.config());
4.205 - state.endpoint = server.config()->server;
4.206 + object->handler = resource;
4.207 }
4.208
4.209 - /* Forbid repeated subscription.
4.210 - NOTE: Could instead rely on being unsubscribed, releasing the existing
4.211 - endpoint. */
4.212 + /* Record the object. */
4.213
4.214 - else
4.215 - return -L4_EEXIST;
4.216 + _monitored.insert(object);
4.217
4.218 - /* Allow this object to be re-entered. This may occur because the subscribe
4.219 - operation can cause deferred notifications to be sent back to the
4.220 - subscribed notifier and to this object. */
4.221 -
4.222 - state_guard.unlock();
4.223 + /* Record this notifier to get general notifications. */
4.224
4.225 - /* Subscribe, sending the notification endpoint via the principal reference
4.226 - for the object. */
4.227 -
4.228 - client_Notification notify(object->base->ref);
4.229 -
4.230 - return notify.subscribe(state.endpoint, flags);
4.231 + return resource->add(this, flags);
4.232 }
4.233
4.234 /* Unsubscribe from notification events on an object. */
4.235
4.236 long ObjectNotifier::unsubscribe(notifiable_t *object)
4.237 {
4.238 - /* Acquire the lock for state lookup. */
4.239 + std::lock_guard<std::mutex> guard(_monitored_lock);
4.240 +
4.241 + if (object->handler == NULL)
4.242 + return L4_EOK;
4.243
4.244 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.245 + NotifierResource *resource = reinterpret_cast<NotifierResource *>(object->handler);
4.246
4.247 - ObjectNotificationState &state = object_state(object, false);
4.248 + _monitored.erase(object);
4.249 + return resource->remove(this);
4.250 +}
4.251 +
4.252 +/* Handle a notification event for an object. */
4.253
4.254 - if (state.is_null())
4.255 - return -L4_ENOENT;
4.256 +void ObjectNotifier::notify(notifiable_t *object)
4.257 +{
4.258 + /* Enter critical section to access the queue. */
4.259
4.260 - /* Unsubscribe via the notification interface. */
4.261 + std::lock_guard<std::mutex> guard(_affected_lock);
4.262 +
4.263 + /* Ensure that a queue entry exists for the object. */
4.264 +
4.265 + NotifiableObjects::iterator it = _affected.find(object);
4.266
4.267 - client_Notification notify(object->base->ref);
4.268 + if (it == _affected.end())
4.269 + {
4.270 + _queued.push_back(object);
4.271 + _affected.insert(object);
4.272 + }
4.273
4.274 - notify.unsubscribe();
4.275 + /* Notify any waiting caller that at least one notification is available. */
4.276
4.277 - return remove_endpoint(object, state.endpoint);
4.278 + _condition.notify_one();
4.279 }
4.280
4.281 -/* Remove a notification endpoint for an object. */
4.282 +/* Wait for notification events on objects, returning each object that has a
4.283 + notification registered for it. */
4.284 +
4.285 +long ObjectNotifier::wait(notifiable_t **object)
4.286 +{
4.287 + /* Enter critical section to access the queue. */
4.288 +
4.289 + std::unique_lock<std::mutex> guard(_affected_lock);
4.290 +
4.291 + while (1)
4.292 + {
4.293 + /* With pending notifications, return the first object. */
4.294
4.295 -long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint)
4.296 + if (!_affected.empty())
4.297 + {
4.298 + *object = _queued.front();
4.299 + _queued.pop_front();
4.300 + _affected.erase(*object);
4.301 + break;
4.302 + }
4.303 +
4.304 + /* Otherwise, wait for notifications. */
4.305 +
4.306 + _condition.wait(guard);
4.307 + }
4.308 +
4.309 + return L4_EOK;
4.310 +}
4.311 +
4.312 +/* Wait for notification events on a specific object. */
4.313 +
4.314 +long ObjectNotifier::wait_object(notifiable_t *object)
4.315 {
4.316 - if (l4_is_invalid_cap(endpoint))
4.317 + if (object->handler == NULL)
4.318 return -L4_EINVAL;
4.319
4.320 - ipc_cap_free_um(endpoint);
4.321 -
4.322 - _state.erase(object);
4.323 -
4.324 - /* Remove the lock for updating object state. */
4.325 -
4.326 - _object_locks.erase(object);
4.327 -
4.328 + reinterpret_cast<NotifierResource *>(object->handler)->wait();
4.329 return L4_EOK;
4.330 }
4.331
4.332
4.333
4.334 -/* Handle a notification event for an object. */
4.335 -
4.336 -void GeneralObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
4.337 - notify_values_t values)
4.338 -{
4.339 - /* Enter critical section for the notifier (affecting all objects). */
4.340 -
4.341 - std::unique_lock<std::mutex> general_guard(_general_lock);
4.342 -
4.343 - /* Acquire the lock for state lookup. */
4.344 -
4.345 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.346 -
4.347 - ObjectNotificationState &state = object_state(object, false);
4.348 -
4.349 - if (state.is_null())
4.350 - return;
4.351 -
4.352 - /* Acquire the lock for the object state itself. */
4.353 -
4.354 - std::unique_lock<std::mutex> object_guard(state.lock);
4.355 -
4.356 - /* Record flags and note previous flags. */
4.357 -
4.358 - notify_flags_t recorded = state.pending_notifications;
4.359 -
4.360 - state.pending_notifications |= flags;
4.361 - state.pending_values = values;
4.362 -
4.363 - /* Add an object queue entry for any objects without previous notifications. */
4.364 -
4.365 - if (!recorded)
4.366 - _affected.push_back(object);
4.367 -
4.368 - /* Notify any waiting caller. */
4.369 -
4.370 - _general_condition.notify_one();
4.371 -}
4.372 +/* Virtual destructor required for base class instance reference deletion. */
4.373
4.374 -void SpecificObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
4.375 - notify_values_t values)
4.376 +NotifierResource::~NotifierResource()
4.377 {
4.378 - /* Acquire the lock for state lookup. */
4.379 -
4.380 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.381 -
4.382 - ObjectNotificationState &state = object_state(object, false);
4.383 -
4.384 - if (state.is_null())
4.385 - return;
4.386 -
4.387 - /* Acquire the lock for the object state itself. */
4.388 -
4.389 - std::unique_lock<std::mutex> object_guard(state.lock);
4.390 -
4.391 - state.pending_notifications |= flags;
4.392 - state.pending_values = values;
4.393 -
4.394 - /* Notify any waiting caller. */
4.395 -
4.396 - state.condition.notify_one();
4.397 -}
4.398 -
4.399 -
4.400 -
4.401 -/* Transfer pending notifications to the given object. This must be called with
4.402 - a lock acquired on the object notification state. */
4.403 -
4.404 -bool ObjectNotifier::_transfer(ObjectNotificationState &state, notifiable_t *object)
4.405 -{
4.406 - notify_flags_t recorded = state.pending_notifications;
4.407 -
4.408 - if (recorded)
4.409 - {
4.410 - object->notifications = recorded;
4.411 - object->values = state.pending_values;
4.412 - state.pending_notifications = 0;
4.413 - return true;
4.414 - }
4.415 -
4.416 - return false;
4.417 }
4.418
4.419 -
4.420 -
4.421 -/* Obtain object state and transfer notifications. */
4.422 -
4.423 -bool GeneralObjectNotifier::_retrieve_for_object(notifiable_t *object)
4.424 -{
4.425 - /* Acquire the lock for state lookup. */
4.426 -
4.427 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.428 -
4.429 - ObjectNotificationState &state = object_state(object, false);
4.430 -
4.431 - if (state.is_null())
4.432 - return false;
4.433 -
4.434 - /* Acquire the lock for the object state itself, then release the state lock. */
4.435 -
4.436 - std::unique_lock<std::mutex> object_guard(state.lock);
4.437 -
4.438 - state_guard.unlock();
4.439 -
4.440 - /* Call generic method to transfer notifications, if possible. */
4.441 -
4.442 - return _transfer(state, object);
4.443 -}
4.444 -
4.445 -/* Obtain queued objects until one is found that still has events recorded for
4.446 - it. This must be called with the notifier's general lock acquired. */
4.447 -
4.448 -bool GeneralObjectNotifier::_retrieve(notifiable_t **object)
4.449 -{
4.450 - while (!_affected.empty())
4.451 - {
4.452 - *object = _affected.front();
4.453 - _affected.pop_front();
4.454 -
4.455 - if (_retrieve_for_object(*object))
4.456 - return true;
4.457 - }
4.458 -
4.459 - return false;
4.460 -}
4.461 -
4.462 -
4.463 -
4.464 -/* Wait for notification events on objects. */
4.465 -
4.466 -long GeneralObjectNotifier::wait(notifiable_t **object)
4.467 -{
4.468 - std::unique_lock<std::mutex> general_guard(_general_lock);
4.469 +/* Handle the release of the resource. */
4.470
4.471 - while (1)
4.472 - {
4.473 - /* With pending notifications, update the first object and exit. */
4.474 -
4.475 - if (_retrieve(object))
4.476 - break;
4.477 -
4.478 - /* Otherwise, wait for notifications. */
4.479 -
4.480 - _general_condition.wait(general_guard);
4.481 - }
4.482 -
4.483 - return L4_EOK;
4.484 -}
4.485 -
4.486 -/* Wait for notifications from a single object. */
4.487 -
4.488 -long SpecificObjectNotifier::wait_object(notifiable_t *object)
4.489 +void NotifierResource::close()
4.490 {
4.491 - /* Acquire the lock for reading object state. */
4.492 -
4.493 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.494 -
4.495 - ObjectNotificationState &state = object_state(object, false);
4.496 -
4.497 - if (state.is_null())
4.498 - return -L4_EINVAL;
4.499 -
4.500 - /* Acquire the lock for the object state itself, then release the state lock. */
4.501 -
4.502 - std::unique_lock<std::mutex> object_guard(state.lock);
4.503 -
4.504 - state_guard.unlock();
4.505 -
4.506 - while (1)
4.507 - {
4.508 - /* With pending notifications, update the object and exit. */
4.509 -
4.510 - if (_transfer(state, object))
4.511 - break;
4.512 -
4.513 - /* Otherwise, wait for notifications. */
4.514 -
4.515 - state.condition.wait(object_guard);
4.516 - }
4.517 -
4.518 - return L4_EOK;
4.519 + _release();
4.520 + _object->handler = NULL;
4.521 }
4.522
4.523 -
4.524 -
4.525 /* Object-specific resource methods. */
4.526
4.527 ipc_server_default_config_type NotifierResource::config()
4.528 @@ -442,14 +237,110 @@
4.529 return config_Notifier;
4.530 }
4.531
4.532 +
4.533 +
4.534 +/* Registration of notifiers. */
4.535 +
4.536 +long NotifierResource::add(ObjectNotifier *notifier, notify_flags_t flags)
4.537 +{
4.538 + std::lock_guard<std::mutex> guard(_lock);
4.539 +
4.540 + bool is_new = _notifiers.empty();
4.541 +
4.542 + _notifiers.insert(notifier);
4.543 +
4.544 + /* Subscribe, sending the notification endpoint via the principal reference
4.545 + for the object. */
4.546 +
4.547 + if (!is_new)
4.548 + return L4_EOK;
4.549 +
4.550 + client_Notification notify(_object->base->ref);
4.551 +
4.552 + return notify.subscribe(endpoint, flags);
4.553 +}
4.554 +
4.555 +long NotifierResource::remove(ObjectNotifier *notifier)
4.556 +{
4.557 + std::lock_guard<std::mutex> guard(_lock);
4.558 +
4.559 + _notifiers.erase(notifier);
4.560 +
4.561 + /* Unsubscribe via the notification interface. */
4.562 +
4.563 + if (!_notifiers.empty())
4.564 + return L4_EOK;
4.565 +
4.566 + client_Notification notify(_object->base->ref);
4.567 +
4.568 + return notify.unsubscribe();
4.569 +}
4.570 +
4.571 +
4.572 +
4.573 /* Register a notification received by an object-specific resource. */
4.574
4.575 long NotifierResource::notify(notify_flags_t flags, notify_values_t values)
4.576 {
4.577 - if (_notifier != NULL)
4.578 - _notifier->notify(_object, flags, values);
4.579 + /* Update the notifiable object. */
4.580
4.581 + _object->notifications |= flags;
4.582 + _object->values = values;
4.583 +
4.584 + _notify();
4.585 return L4_EOK;
4.586 }
4.587
4.588 -// vim: tabstop=2 expandtab shiftwidth=2
4.589 +void NotifierResource::_notify()
4.590 +{
4.591 + /* Enter critical section for the resource. */
4.592 +
4.593 + std::lock_guard<std::mutex> guard(_lock);
4.594 +
4.595 + /* Record a pending notification which persists if nothing is waiting. */
4.596 +
4.597 + _pending = true;
4.598 +
4.599 + /* Notify any party waiting specifically on this object. */
4.600 +
4.601 + _condition.notify_one();
4.602 +
4.603 + /* Register the notification with all notifier objects. */
4.604 +
4.605 + ObjectNotifiers::iterator it;
4.606 +
4.607 + for (it = _notifiers.begin(); it != _notifiers.end(); it++)
4.608 + (*it)->notify(_object);
4.609 +}
4.610 +
4.611 +void NotifierResource::_release()
4.612 +{
4.613 + /* Enter critical section for the resource. */
4.614 +
4.615 + std::lock_guard<std::mutex> guard(_lock);
4.616 +
4.617 + ObjectNotifiers::iterator it;
4.618 +
4.619 + for (it = _notifiers.begin(); it != _notifiers.end(); it++)
4.620 + (*it)->release(_object);
4.621 +}
4.622 +
4.623 +/* Wait for notification events on a specific object. */
4.624 +
4.625 +long NotifierResource::wait()
4.626 +{
4.627 + /* Enter critical section for the resource. */
4.628 +
4.629 + std::unique_lock<std::mutex> guard(_lock);
4.630 +
4.631 + /* Wait for the notification condition. */
4.632 +
4.633 + if (!_pending)
4.634 + _condition.wait(guard);
4.635 +
4.636 + _pending = false;
4.637 + return L4_EOK;
4.638 +}
4.639 +
4.640 +/* vim: tabstop=2 expandtab shiftwidth=2
4.641 +*/
5.1 --- a/libsystypes/include/systypes/base.h Wed Mar 29 00:32:20 2023 +0200
5.2 +++ b/libsystypes/include/systypes/base.h Mon Apr 03 00:35:34 2023 +0200
5.3 @@ -77,6 +77,7 @@
5.4 notifiable_base_t *base; /* access to the specific object */
5.5 notify_flags_t notifications; /* essential notifications */
5.6 notify_values_t values; /* signal-specific values */
5.7 + void *handler; /* associated notification handler */
5.8
5.9 } notifiable_t;
5.10
6.1 --- a/tests/dstest_file_monitor.cc Wed Mar 29 00:32:20 2023 +0200
6.2 +++ b/tests/dstest_file_monitor.cc Mon Apr 03 00:35:34 2023 +0200
6.3 @@ -56,6 +56,7 @@
6.4 {
6.5 sprintf(buffer, "%s/file%02d", filename, i);
6.6
6.7 + printf("Open file %d.\n", i);
6.8 client_open(buffer, O_CREAT | O_RDWR);
6.9 sleep(1);
6.10 }
6.11 @@ -65,21 +66,13 @@
6.12
6.13 static void monitor_files(file_t *directory)
6.14 {
6.15 - long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task());
6.16 -
6.17 - if (err)
6.18 - {
6.19 - printf("Could not subscribe to events on directory.\n");
6.20 - return;
6.21 - }
6.22 -
6.23 int expected;
6.24
6.25 for (expected = FILES_TO_OPEN; expected; expected--)
6.26 {
6.27 /* Wait for notification of content. */
6.28
6.29 - err = client_wait_file(directory, client_notifier_task());
6.30 + long err = client_wait_file(directory, client_notifier_task());
6.31
6.32 if (err)
6.33 {
6.34 @@ -116,6 +109,14 @@
6.35 return 1;
6.36 }
6.37
6.38 + long err = client_subscribe(directory, NOTIFY_FILE_OPENED, client_notifier_task());
6.39 +
6.40 + if (err)
6.41 + {
6.42 + printf("Could not subscribe to events on directory.\n");
6.43 + return 1;
6.44 + }
6.45 +
6.46 /* Schedule threads. */
6.47
6.48 std::thread *activities[2];
6.49 @@ -127,6 +128,9 @@
6.50 activities[i]->join();
6.51
6.52 printf("Expected %d 'file opened' notifications.\n", FILES_TO_OPEN);
6.53 +
6.54 + client_close(directory);
6.55 +
6.56 printf("End of test.\n");
6.57 return 0;
6.58 }