1.1 --- a/libfsclient/Control Mon Mar 20 14:52:03 2023 +0100
1.2 +++ b/libfsclient/Control Mon Mar 20 22:28:37 2023 +0100
1.3 @@ -1,3 +1,3 @@
1.4 -requires: libstdc++ libc libipc libmem
1.5 +requires: libstdc++ libc libipc libmem libnotifier
1.6 provides: libfsclient
1.7 maintainer: paul@boddie.org.uk
2.1 --- a/libfsclient/include/fsclient/notifier.h Mon Mar 20 14:52:03 2023 +0100
2.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2.3 @@ -1,175 +0,0 @@
2.4 -/*
2.5 - * Generic object event notification support.
2.6 - *
2.7 - * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
2.8 - *
2.9 - * This program is free software; you can redistribute it and/or
2.10 - * modify it under the terms of the GNU General Public License as
2.11 - * published by the Free Software Foundation; either version 2 of
2.12 - * the License, or (at your option) any later version.
2.13 - *
2.14 - * This program is distributed in the hope that it will be useful,
2.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.17 - * GNU General Public License for more details.
2.18 - *
2.19 - * You should have received a copy of the GNU General Public License
2.20 - * along with this program; if not, write to the Free Software
2.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
2.22 - * Boston, MA 02110-1301, USA
2.23 - */
2.24 -
2.25 -#pragma once
2.26 -
2.27 -#include <condition_variable>
2.28 -#include <list>
2.29 -#include <map>
2.30 -#include <mutex>
2.31 -
2.32 -#include <fsclient/file.h>
2.33 -#include <systypes/base.h>
2.34 -
2.35 -
2.36 -
2.37 -/* Object-specific notification details. */
2.38 -
2.39 -class ObjectNotificationState
2.40 -{
2.41 -public:
2.42 - /* Synchronisation primitives for state access and notification. */
2.43 -
2.44 - std::mutex lock;
2.45 - std::condition_variable condition;
2.46 -
2.47 - /* Pending notifications for monitored objects. */
2.48 -
2.49 - notify_flags_t pending_notifications = 0;
2.50 - notify_values_t pending_values = NOTIFY_VALUES_NULL;
2.51 -
2.52 - /* Endpoints associated with monitored objects. */
2.53 -
2.54 - l4_cap_idx_t endpoint = L4_INVALID_CAP;
2.55 -
2.56 - bool is_null() { return l4_is_invalid_cap(endpoint); }
2.57 -};
2.58 -
2.59 -
2.60 -
2.61 -/* Collection types. */
2.62 -
2.63 -typedef std::map<notifiable_t *, ObjectNotificationState> ObjectNotificationStates;
2.64 -typedef std::map<notifiable_t *, std::mutex> ObjectStateLocks;
2.65 -
2.66 -
2.67 -
2.68 -/* An object for monitoring object event notifications. */
2.69 -
2.70 -class ObjectNotifier
2.71 -{
2.72 -protected:
2.73 - /* General state access locking. */
2.74 -
2.75 - std::mutex _state_lock;
2.76 -
2.77 - /* Object-specific state locking. */
2.78 -
2.79 - ObjectStateLocks _object_locks;
2.80 -
2.81 - /* Notification state. */
2.82 -
2.83 - ObjectNotificationStates _state;
2.84 -
2.85 - /* Notifier thread details. */
2.86 -
2.87 - l4_cap_idx_t _thread = L4_INVALID_CAP;
2.88 - bool _started = false;
2.89 -
2.90 - /* Convenience method to access object state. */
2.91 -
2.92 - virtual ObjectNotificationState &object_state(notifiable_t *object, bool create);
2.93 -
2.94 - /* Helper methods. */
2.95 -
2.96 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.97 - notify_values_t values) = 0;
2.98 -
2.99 - virtual bool _transfer(ObjectNotificationState &state, notifiable_t *object);
2.100 -
2.101 -public:
2.102 - virtual ~ObjectNotifier();
2.103 -
2.104 - /* Local operations. */
2.105 -
2.106 - virtual long start();
2.107 -
2.108 - virtual long subscribe(notifiable_t *object, notify_flags_t flags);
2.109 -
2.110 - virtual long unsubscribe(notifiable_t *object);
2.111 -
2.112 - virtual long get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create);
2.113 -
2.114 - virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
2.115 -
2.116 - /* Event handling support. */
2.117 -
2.118 - virtual void mainloop();
2.119 -};
2.120 -
2.121 -
2.122 -
2.123 -/* An object monitoring notifications for a collection of different objects. */
2.124 -
2.125 -class GeneralObjectNotifier : public ObjectNotifier
2.126 -{
2.127 -protected:
2.128 - /* Locking to protect pending notification members and to coordinate access
2.129 - to notifications. */
2.130 -
2.131 - std::mutex _general_lock;
2.132 -
2.133 - /* General lock synchronisation. */
2.134 -
2.135 - std::condition_variable _general_condition;
2.136 -
2.137 - /* Objects affected by notifications. */
2.138 -
2.139 - std::list<notifiable_t *> _affected;
2.140 -
2.141 - /* Helper methods. */
2.142 -
2.143 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.144 - notify_values_t values);
2.145 -
2.146 - virtual bool _retrieve(notifiable_t **object);
2.147 -
2.148 - virtual bool _retrieve_for_object(notifiable_t *object);
2.149 -
2.150 -public:
2.151 - virtual long wait(notifiable_t **object);
2.152 -};
2.153 -
2.154 -
2.155 -
2.156 -/* An object monitoring notifications for specific objects. */
2.157 -
2.158 -class SpecificObjectNotifier : public ObjectNotifier
2.159 -{
2.160 -protected:
2.161 - /* Helper methods. */
2.162 -
2.163 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.164 - notify_values_t values);
2.165 -
2.166 -public:
2.167 - virtual long wait_object(notifiable_t *object);
2.168 -};
2.169 -
2.170 -
2.171 -
2.172 -/* Helper functions. */
2.173 -
2.174 -SpecificObjectNotifier *notifier_get_task_notifier();
2.175 -
2.176 -GeneralObjectNotifier *notifier_get_local_notifier();
2.177 -
2.178 -// vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/libfsclient/lib/src/Makefile Mon Mar 20 14:52:03 2023 +0100
3.2 +++ b/libfsclient/lib/src/Makefile Mon Mar 20 22:28:37 2023 +0100
3.3 @@ -16,14 +16,14 @@
3.4 # Individual interfaces.
3.5
3.6 CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \
3.7 - mapped_file notifier notification opener \
3.8 - opener_context pipe pipe_opener process_creator_context
3.9 + mapped_file opener opener_context \
3.10 + pipe pipe_opener process_creator_context
3.11
3.12 # Generated and plain source files.
3.13
3.14 CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
3.15
3.16 -PLAIN_SRC_CC = client.cc file.cc notifier.cc process.cc
3.17 +PLAIN_SRC_CC = client.cc file.cc process.cc
3.18
3.19 # Normal definitions.
3.20
3.21 @@ -31,7 +31,7 @@
3.22 $(CLIENT_INTERFACES_SRC_CC) \
3.23 $(PLAIN_SRC_CC)
3.24
3.25 -REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes libmem
3.26 +REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes libmem libnotifier
3.27
3.28 PRIVATE_INCDIR = $(PKGDIR)/include/fsclient $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
3.29 CONTRIB_INCDIR = libfsclient
4.1 --- a/libfsclient/lib/src/file.cc Mon Mar 20 14:52:03 2023 +0100
4.2 +++ b/libfsclient/lib/src/file.cc Mon Mar 20 22:28:37 2023 +0100
4.3 @@ -21,6 +21,7 @@
4.4
4.5 #include <ipc/cap_alloc.h>
4.6 #include <ipc/mem_ipc.h>
4.7 +#include <notifier/notifier.h>
4.8 #include <systypes/fcntl.h>
4.9 #include <systypes/stat.h>
4.10
4.11 @@ -39,7 +40,6 @@
4.12 #include "mapped_file_client.h"
4.13
4.14 #include "file.h"
4.15 -#include "notifier.h"
4.16
4.17
4.18
5.1 --- a/libfsclient/lib/src/notifier.cc Mon Mar 20 14:52:03 2023 +0100
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,458 +0,0 @@
5.4 -/*
5.5 - * Generic object event notification support.
5.6 - *
5.7 - * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
5.8 - *
5.9 - * This program is free software; you can redistribute it and/or
5.10 - * modify it under the terms of the GNU General Public License as
5.11 - * published by the Free Software Foundation; either version 2 of
5.12 - * the License, or (at your option) any later version.
5.13 - *
5.14 - * This program is distributed in the hope that it will be useful,
5.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.17 - * GNU General Public License for more details.
5.18 - *
5.19 - * You should have received a copy of the GNU General Public License
5.20 - * along with this program; if not, write to the Free Software
5.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
5.22 - * Boston, MA 02110-1301, USA
5.23 - */
5.24 -
5.25 -#include <map>
5.26 -#include <mutex>
5.27 -
5.28 -#include <ipc/cap_alloc.h>
5.29 -#include <ipc/server.h>
5.30 -
5.31 -#include <pthread.h>
5.32 -#include <pthread-l4.h>
5.33 -
5.34 -#include "notification_client.h"
5.35 -#include "notifier.h"
5.36 -#include "notifier_interface.h"
5.37 -
5.38 -
5.39 -
5.40 -/* Null notification state. */
5.41 -
5.42 -static ObjectNotificationState _null_state;
5.43 -
5.44 -
5.45 -
5.46 -/* Lock protecting per-task notifier access. */
5.47 -
5.48 -static std::mutex _lock;
5.49 -
5.50 -/* Per-task storage for specific waiting operations. */
5.51 -
5.52 -static SpecificObjectNotifier *_notifier = NULL;
5.53 -
5.54 -
5.55 -
5.56 -/* Return the per-task notifier for object-specific waiting operations. */
5.57 -
5.58 -SpecificObjectNotifier *notifier_get_task_notifier()
5.59 -{
5.60 - std::lock_guard<std::mutex> guard(_lock);
5.61 -
5.62 - /* Start any new notifier. */
5.63 -
5.64 - if (_notifier == NULL)
5.65 - {
5.66 - _notifier = new SpecificObjectNotifier;
5.67 - _notifier->start();
5.68 - }
5.69 -
5.70 - return _notifier;
5.71 -}
5.72 -
5.73 -/* Return a local notifier for general object waiting operations. */
5.74 -
5.75 -GeneralObjectNotifier *notifier_get_local_notifier()
5.76 -{
5.77 - GeneralObjectNotifier *notifier = new GeneralObjectNotifier;
5.78 -
5.79 - notifier->start();
5.80 - return notifier;
5.81 -}
5.82 -
5.83 -
5.84 -
5.85 -/* Invoke the mainloop in a thread. */
5.86 -
5.87 -static void *notifier_mainloop(void *data)
5.88 -{
5.89 - ObjectNotifier *notifier = reinterpret_cast<ObjectNotifier *>(data);
5.90 -
5.91 - notifier->mainloop();
5.92 - return 0;
5.93 -}
5.94 -
5.95 -
5.96 -
5.97 -/* Virtual destructor required for base class instance reference deletion. */
5.98 -
5.99 -ObjectNotifier::~ObjectNotifier()
5.100 -{
5.101 -}
5.102 -
5.103 -/* Listen for notifications. */
5.104 -
5.105 -void ObjectNotifier::mainloop()
5.106 -{
5.107 - ipc_message_t msg;
5.108 - l4_umword_t label;
5.109 -
5.110 - while (1)
5.111 - {
5.112 - ipc_message_wait(&msg, &label);
5.113 -
5.114 - /* Clear lower label bits. */
5.115 -
5.116 - label = label & ~3UL;
5.117 -
5.118 - /* Ignore erroneous messages. */
5.119 -
5.120 - if (l4_ipc_error(msg.tag, l4_utcb()))
5.121 - continue;
5.122 -
5.123 - /* Interpret gate labels as notifiable objects. */
5.124 -
5.125 - notifiable_t *object = (notifiable_t *) label;
5.126 -
5.127 - /* Obtain message details. */
5.128 -
5.129 - ipc_message_open(&msg);
5.130 -
5.131 - struct in_words_Notifier_notify *in_words = (struct in_words_Notifier_notify *) ipc_message_get_word_address(&msg, 0);
5.132 -
5.133 - /* Reply to notifications. */
5.134 -
5.135 - ipc_message_reply(&msg);
5.136 - ipc_message_discard(&msg);
5.137 -
5.138 - /* Register the notification. */
5.139 -
5.140 - _notify(object, in_words->flags, in_words->values);
5.141 - }
5.142 -
5.143 - ipc_message_free(&msg);
5.144 -}
5.145 -
5.146 -/* Start listening for notifications. */
5.147 -
5.148 -long ObjectNotifier::start()
5.149 -{
5.150 - if (_started)
5.151 - return L4_EOK;
5.152 -
5.153 - pthread_t thread;
5.154 - pthread_attr_t attr;
5.155 - long err;
5.156 -
5.157 - pthread_attr_init(&attr);
5.158 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5.159 -
5.160 - err = pthread_create(&thread, &attr, notifier_mainloop, this);
5.161 - if (err)
5.162 - return err;
5.163 -
5.164 - _thread = pthread_l4_cap(thread);
5.165 - _started = true;
5.166 -
5.167 - return L4_EOK;
5.168 -}
5.169 -
5.170 -
5.171 -
5.172 -/* Return notification state for the given object or null state if no record
5.173 - existed for the object. */
5.174 -
5.175 -ObjectNotificationState &ObjectNotifier::object_state(notifiable_t *object, bool create)
5.176 -{
5.177 - ObjectNotificationStates::iterator it = _state.find(object);
5.178 -
5.179 - if (it == _state.end())
5.180 - {
5.181 - if (create)
5.182 - return _state[object];
5.183 - else
5.184 - return _null_state;
5.185 - }
5.186 -
5.187 - return it->second;
5.188 -}
5.189 -
5.190 -/* Subscribe to notification events on an object. */
5.191 -
5.192 -long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
5.193 -{
5.194 - l4_cap_idx_t endpoint;
5.195 - long err = get_endpoint(object, &endpoint, true);
5.196 -
5.197 - if (err)
5.198 - return err;
5.199 -
5.200 - /* Subscribe, sending the notification endpoint via the principal reference
5.201 - for the object. */
5.202 -
5.203 - client_Notification notify(object->base->ref);
5.204 -
5.205 - return notify.subscribe(endpoint, flags);
5.206 -}
5.207 -
5.208 -/* Unsubscribe from notification events on an object. */
5.209 -
5.210 -long ObjectNotifier::unsubscribe(notifiable_t *object)
5.211 -{
5.212 - l4_cap_idx_t endpoint;
5.213 - long err = get_endpoint(object, &endpoint, false);
5.214 -
5.215 - if (err)
5.216 - return err;
5.217 -
5.218 - /* Unsubscribe via the notification interface. */
5.219 -
5.220 - client_Notification notify(object->base->ref);
5.221 -
5.222 - notify.unsubscribe(endpoint);
5.223 -
5.224 - return remove_endpoint(object, endpoint);
5.225 -}
5.226 -
5.227 -/* Obtain a notification endpoint for an object. */
5.228 -
5.229 -long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create)
5.230 -{
5.231 - /* Acquire the lock for state lookup. */
5.232 -
5.233 - std::unique_lock<std::mutex> state_guard(_state_lock);
5.234 -
5.235 - ObjectNotificationState &state = object_state(object, create);
5.236 -
5.237 - /* Create a notification endpoint, if necessary. */
5.238 -
5.239 - if (state.is_null())
5.240 - {
5.241 - if (create)
5.242 - {
5.243 - long err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
5.244 -
5.245 - if (err)
5.246 - return err;
5.247 - }
5.248 - else
5.249 - return -L4_ENOENT;
5.250 - }
5.251 -
5.252 - *endpoint = state.endpoint;
5.253 - return L4_EOK;
5.254 -}
5.255 -
5.256 -/* Remove a notification endpoint for an object. */
5.257 -
5.258 -long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint)
5.259 -{
5.260 - if (l4_is_invalid_cap(endpoint))
5.261 - return -L4_EINVAL;
5.262 -
5.263 - ipc_cap_free_um(endpoint);
5.264 -
5.265 - _state.erase(object);
5.266 -
5.267 - /* Remove the lock for updating object state. */
5.268 -
5.269 - _object_locks.erase(object);
5.270 -
5.271 - return L4_EOK;
5.272 -}
5.273 -
5.274 -
5.275 -
5.276 -/* Handle a notification event for an object. Ideally, this would be invoked by
5.277 - the generic server dispatch mechanism, with the gate label being interpreted
5.278 - and provided as the first parameter. */
5.279 -
5.280 -void GeneralObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
5.281 - notify_values_t values)
5.282 -{
5.283 - /* Enter critical section for the notifier (affecting all objects). */
5.284 -
5.285 - std::unique_lock<std::mutex> general_guard(_general_lock);
5.286 -
5.287 - /* Acquire the lock for state lookup. */
5.288 -
5.289 - std::unique_lock<std::mutex> state_guard(_state_lock);
5.290 -
5.291 - ObjectNotificationState &state = object_state(object, false);
5.292 -
5.293 - if (state.is_null())
5.294 - return;
5.295 -
5.296 - /* Acquire the lock for the object state itself. */
5.297 -
5.298 - std::unique_lock<std::mutex> object_guard(state.lock);
5.299 -
5.300 - /* Record flags and note previous flags. */
5.301 -
5.302 - notify_flags_t recorded = state.pending_notifications;
5.303 -
5.304 - state.pending_notifications |= flags;
5.305 - state.pending_values = values;
5.306 -
5.307 - /* Add an object queue entry for any objects without previous notifications. */
5.308 -
5.309 - if (!recorded)
5.310 - _affected.push_back(object);
5.311 -
5.312 - /* Notify any waiting caller. */
5.313 -
5.314 - _general_condition.notify_one();
5.315 -}
5.316 -
5.317 -void SpecificObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
5.318 - notify_values_t values)
5.319 -{
5.320 - /* Acquire the lock for state lookup. */
5.321 -
5.322 - std::unique_lock<std::mutex> state_guard(_state_lock);
5.323 -
5.324 - ObjectNotificationState &state = object_state(object, false);
5.325 -
5.326 - if (state.is_null())
5.327 - return;
5.328 -
5.329 - /* Acquire the lock for the object state itself. */
5.330 -
5.331 - std::unique_lock<std::mutex> object_guard(state.lock);
5.332 -
5.333 - state.pending_notifications |= flags;
5.334 - state.pending_values = values;
5.335 -
5.336 - /* Notify any waiting caller. */
5.337 -
5.338 - state.condition.notify_one();
5.339 -}
5.340 -
5.341 -
5.342 -
5.343 -/* Transfer pending notifications to the given object. This must be called with
5.344 - a lock acquired on the object notification state. */
5.345 -
5.346 -bool ObjectNotifier::_transfer(ObjectNotificationState &state, notifiable_t *object)
5.347 -{
5.348 - notify_flags_t recorded = state.pending_notifications;
5.349 -
5.350 - if (recorded)
5.351 - {
5.352 - object->notifications = recorded;
5.353 - object->values = state.pending_values;
5.354 - state.pending_notifications = 0;
5.355 - return true;
5.356 - }
5.357 -
5.358 - return false;
5.359 -}
5.360 -
5.361 -
5.362 -
5.363 -/* Obtain object state and transfer notifications. */
5.364 -
5.365 -bool GeneralObjectNotifier::_retrieve_for_object(notifiable_t *object)
5.366 -{
5.367 - /* Acquire the lock for state lookup. */
5.368 -
5.369 - std::unique_lock<std::mutex> state_guard(_state_lock);
5.370 -
5.371 - ObjectNotificationState &state = object_state(object, false);
5.372 -
5.373 - if (state.is_null())
5.374 - return false;
5.375 -
5.376 - /* Acquire the lock for the object state itself, then release the state lock. */
5.377 -
5.378 - std::unique_lock<std::mutex> object_guard(state.lock);
5.379 -
5.380 - state_guard.unlock();
5.381 -
5.382 - /* Call generic method to transfer notifications, if possible. */
5.383 -
5.384 - return _transfer(state, object);
5.385 -}
5.386 -
5.387 -/* Obtain queued objects until one is found that still has events recorded for
5.388 - it. This must be called with the notifier's general lock acquired. */
5.389 -
5.390 -bool GeneralObjectNotifier::_retrieve(notifiable_t **object)
5.391 -{
5.392 - while (!_affected.empty())
5.393 - {
5.394 - *object = _affected.front();
5.395 - _affected.pop_front();
5.396 -
5.397 - if (_retrieve_for_object(*object))
5.398 - return true;
5.399 - }
5.400 -
5.401 - return false;
5.402 -}
5.403 -
5.404 -
5.405 -
5.406 -/* Wait for notification events on objects. */
5.407 -
5.408 -long GeneralObjectNotifier::wait(notifiable_t **object)
5.409 -{
5.410 - std::unique_lock<std::mutex> general_guard(_general_lock);
5.411 -
5.412 - while (1)
5.413 - {
5.414 - /* With pending notifications, update the first object and exit. */
5.415 -
5.416 - if (_retrieve(object))
5.417 - break;
5.418 -
5.419 - /* Otherwise, wait for notifications. */
5.420 -
5.421 - _general_condition.wait(general_guard);
5.422 - }
5.423 -
5.424 - return L4_EOK;
5.425 -}
5.426 -
5.427 -/* Wait for notifications from a single object. */
5.428 -
5.429 -long SpecificObjectNotifier::wait_object(notifiable_t *object)
5.430 -{
5.431 - /* Acquire the lock for reading object state. */
5.432 -
5.433 - std::unique_lock<std::mutex> state_guard(_state_lock);
5.434 -
5.435 - ObjectNotificationState &state = object_state(object, false);
5.436 -
5.437 - if (state.is_null())
5.438 - return -L4_EINVAL;
5.439 -
5.440 - /* Acquire the lock for the object state itself, then release the state lock. */
5.441 -
5.442 - std::unique_lock<std::mutex> object_guard(state.lock);
5.443 -
5.444 - state_guard.unlock();
5.445 -
5.446 - while (1)
5.447 - {
5.448 - /* With pending notifications, update the object and exit. */
5.449 -
5.450 - if (_transfer(state, object))
5.451 - break;
5.452 -
5.453 - /* Otherwise, wait for notifications. */
5.454 -
5.455 - state.condition.wait(object_guard);
5.456 - }
5.457 -
5.458 - return L4_EOK;
5.459 -}
5.460 -
5.461 -// vim: tabstop=2 expandtab shiftwidth=2
6.1 --- a/libfsclient/lib/src/process.cc Mon Mar 20 14:52:03 2023 +0100
6.2 +++ b/libfsclient/lib/src/process.cc Mon Mar 20 22:28:37 2023 +0100
6.3 @@ -21,6 +21,7 @@
6.4
6.5 #include <ipc/cap_alloc.h>
6.6 #include <ipc/mem_ipc.h>
6.7 +#include <notifier/notifier.h>
6.8 #include <systypes/env.h>
6.9
6.10 #include <stdio.h>
6.11 @@ -30,7 +31,6 @@
6.12
6.13 #include "file.h"
6.14 #include "process.h"
6.15 -#include "notifier.h"
6.16
6.17
6.18
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/libnotifier/Control Mon Mar 20 22:28:37 2023 +0100
7.3 @@ -0,0 +1,3 @@
7.4 +requires: libstdc++ libc libipc
7.5 +provides: libnotifier
7.6 +maintainer: paul@boddie.org.uk
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/libnotifier/Makefile Mon Mar 20 22:28:37 2023 +0100
8.3 @@ -0,0 +1,4 @@
8.4 +PKGDIR ?= .
8.5 +L4DIR ?= $(PKGDIR)/../../..
8.6 +
8.7 +include $(L4DIR)/mk/subdir.mk
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/libnotifier/include/Makefile Mon Mar 20 22:28:37 2023 +0100
9.3 @@ -0,0 +1,7 @@
9.4 +PKGDIR ?= ..
9.5 +L4DIR ?= $(PKGDIR)/../../..
9.6 +
9.7 +PKGNAME = libnotifier
9.8 +CONTRIB_HEADERS = 1
9.9 +
9.10 +include $(L4DIR)/mk/include.mk
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/libnotifier/include/notifier/notifier.h Mon Mar 20 22:28:37 2023 +0100
10.3 @@ -0,0 +1,174 @@
10.4 +/*
10.5 + * Generic object event notification support.
10.6 + *
10.7 + * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
10.8 + *
10.9 + * This program is free software; you can redistribute it and/or
10.10 + * modify it under the terms of the GNU General Public License as
10.11 + * published by the Free Software Foundation; either version 2 of
10.12 + * the License, or (at your option) any later version.
10.13 + *
10.14 + * This program is distributed in the hope that it will be useful,
10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.17 + * GNU General Public License for more details.
10.18 + *
10.19 + * You should have received a copy of the GNU General Public License
10.20 + * along with this program; if not, write to the Free Software
10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
10.22 + * Boston, MA 02110-1301, USA
10.23 + */
10.24 +
10.25 +#pragma once
10.26 +
10.27 +#include <condition_variable>
10.28 +#include <list>
10.29 +#include <map>
10.30 +#include <mutex>
10.31 +
10.32 +#include <systypes/base.h>
10.33 +
10.34 +
10.35 +
10.36 +/* Object-specific notification details. */
10.37 +
10.38 +class ObjectNotificationState
10.39 +{
10.40 +public:
10.41 + /* Synchronisation primitives for state access and notification. */
10.42 +
10.43 + std::mutex lock;
10.44 + std::condition_variable condition;
10.45 +
10.46 + /* Pending notifications for monitored objects. */
10.47 +
10.48 + notify_flags_t pending_notifications = 0;
10.49 + notify_values_t pending_values = NOTIFY_VALUES_NULL;
10.50 +
10.51 + /* Endpoints associated with monitored objects. */
10.52 +
10.53 + l4_cap_idx_t endpoint = L4_INVALID_CAP;
10.54 +
10.55 + bool is_null() { return l4_is_invalid_cap(endpoint); }
10.56 +};
10.57 +
10.58 +
10.59 +
10.60 +/* Collection types. */
10.61 +
10.62 +typedef std::map<notifiable_t *, ObjectNotificationState> ObjectNotificationStates;
10.63 +typedef std::map<notifiable_t *, std::mutex> ObjectStateLocks;
10.64 +
10.65 +
10.66 +
10.67 +/* An object for monitoring object event notifications. */
10.68 +
10.69 +class ObjectNotifier
10.70 +{
10.71 +protected:
10.72 + /* General state access locking. */
10.73 +
10.74 + std::mutex _state_lock;
10.75 +
10.76 + /* Object-specific state locking. */
10.77 +
10.78 + ObjectStateLocks _object_locks;
10.79 +
10.80 + /* Notification state. */
10.81 +
10.82 + ObjectNotificationStates _state;
10.83 +
10.84 + /* Notifier thread details. */
10.85 +
10.86 + l4_cap_idx_t _thread = L4_INVALID_CAP;
10.87 + bool _started = false;
10.88 +
10.89 + /* Convenience method to access object state. */
10.90 +
10.91 + virtual ObjectNotificationState &object_state(notifiable_t *object, bool create);
10.92 +
10.93 + /* Helper methods. */
10.94 +
10.95 + virtual void _notify(notifiable_t *object, notify_flags_t flags,
10.96 + notify_values_t values) = 0;
10.97 +
10.98 + virtual bool _transfer(ObjectNotificationState &state, notifiable_t *object);
10.99 +
10.100 +public:
10.101 + virtual ~ObjectNotifier();
10.102 +
10.103 + /* Local operations. */
10.104 +
10.105 + virtual long start();
10.106 +
10.107 + virtual long subscribe(notifiable_t *object, notify_flags_t flags);
10.108 +
10.109 + virtual long unsubscribe(notifiable_t *object);
10.110 +
10.111 + virtual long get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create);
10.112 +
10.113 + virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
10.114 +
10.115 + /* Event handling support. */
10.116 +
10.117 + virtual void mainloop();
10.118 +};
10.119 +
10.120 +
10.121 +
10.122 +/* An object monitoring notifications for a collection of different objects. */
10.123 +
10.124 +class GeneralObjectNotifier : public ObjectNotifier
10.125 +{
10.126 +protected:
10.127 + /* Locking to protect pending notification members and to coordinate access
10.128 + to notifications. */
10.129 +
10.130 + std::mutex _general_lock;
10.131 +
10.132 + /* General lock synchronisation. */
10.133 +
10.134 + std::condition_variable _general_condition;
10.135 +
10.136 + /* Objects affected by notifications. */
10.137 +
10.138 + std::list<notifiable_t *> _affected;
10.139 +
10.140 + /* Helper methods. */
10.141 +
10.142 + virtual void _notify(notifiable_t *object, notify_flags_t flags,
10.143 + notify_values_t values);
10.144 +
10.145 + virtual bool _retrieve(notifiable_t **object);
10.146 +
10.147 + virtual bool _retrieve_for_object(notifiable_t *object);
10.148 +
10.149 +public:
10.150 + virtual long wait(notifiable_t **object);
10.151 +};
10.152 +
10.153 +
10.154 +
10.155 +/* An object monitoring notifications for specific objects. */
10.156 +
10.157 +class SpecificObjectNotifier : public ObjectNotifier
10.158 +{
10.159 +protected:
10.160 + /* Helper methods. */
10.161 +
10.162 + virtual void _notify(notifiable_t *object, notify_flags_t flags,
10.163 + notify_values_t values);
10.164 +
10.165 +public:
10.166 + virtual long wait_object(notifiable_t *object);
10.167 +};
10.168 +
10.169 +
10.170 +
10.171 +/* Helper functions. */
10.172 +
10.173 +SpecificObjectNotifier *notifier_get_task_notifier();
10.174 +
10.175 +GeneralObjectNotifier *notifier_get_local_notifier();
10.176 +
10.177 +// vim: tabstop=4 expandtab shiftwidth=4
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/libnotifier/lib/Makefile Mon Mar 20 22:28:37 2023 +0100
11.3 @@ -0,0 +1,4 @@
11.4 +PKGDIR ?= ..
11.5 +L4DIR ?= $(PKGDIR)/../../..
11.6 +
11.7 +include $(L4DIR)/mk/subdir.mk
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/libnotifier/lib/src/Makefile Mon Mar 20 22:28:37 2023 +0100
12.3 @@ -0,0 +1,40 @@
12.4 +PKGDIR ?= ../..
12.5 +L4DIR ?= $(PKGDIR)/../../..
12.6 +
12.7 +TARGET = libnotifier.so libnotifier.a
12.8 +PC_FILENAME = libnotifier
12.9 +
12.10 +# Locations for interface input and generated output.
12.11 +
12.12 +IDL_DIR = $(PKGDIR)/../libsystypes/idl
12.13 +IDL_MK_DIR = $(L4DIR)/idl4re/mk
12.14 +IDL_BUILD_DIR = .
12.15 +IDL_EXPORT_DIR = .
12.16 +
12.17 +include $(IDL_MK_DIR)/idl.mk
12.18 +
12.19 +# Individual interfaces.
12.20 +
12.21 +CLIENT_INTERFACES_CC = notifier notification
12.22 +
12.23 +# Generated and plain source files.
12.24 +
12.25 +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
12.26 +
12.27 +PLAIN_SRC_CC = notifier.cc
12.28 +
12.29 +# Normal definitions.
12.30 +
12.31 +SRC_CC = \
12.32 + $(CLIENT_INTERFACES_SRC_CC) \
12.33 + $(PLAIN_SRC_CC)
12.34 +
12.35 +REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes
12.36 +
12.37 +PRIVATE_INCDIR = $(PKGDIR)/include/notifier $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
12.38 +CONTRIB_INCDIR = libnotifier
12.39 +
12.40 +include $(L4DIR)/mk/lib.mk
12.41 +include $(IDL_MK_DIR)/interface_rules.mk
12.42 +
12.43 +$(PLAIN_SRC_CC): $(CLIENT_INTERFACES_SRC_CC)
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/libnotifier/lib/src/notifier.cc Mon Mar 20 22:28:37 2023 +0100
13.3 @@ -0,0 +1,458 @@
13.4 +/*
13.5 + * Generic object event notification support.
13.6 + *
13.7 + * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
13.8 + *
13.9 + * This program is free software; you can redistribute it and/or
13.10 + * modify it under the terms of the GNU General Public License as
13.11 + * published by the Free Software Foundation; either version 2 of
13.12 + * the License, or (at your option) any later version.
13.13 + *
13.14 + * This program is distributed in the hope that it will be useful,
13.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13.17 + * GNU General Public License for more details.
13.18 + *
13.19 + * You should have received a copy of the GNU General Public License
13.20 + * along with this program; if not, write to the Free Software
13.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
13.22 + * Boston, MA 02110-1301, USA
13.23 + */
13.24 +
13.25 +#include <map>
13.26 +#include <mutex>
13.27 +
13.28 +#include <ipc/cap_alloc.h>
13.29 +#include <ipc/server.h>
13.30 +
13.31 +#include <pthread.h>
13.32 +#include <pthread-l4.h>
13.33 +
13.34 +#include "notification_client.h"
13.35 +#include "notifier.h"
13.36 +#include "notifier_interface.h"
13.37 +
13.38 +
13.39 +
13.40 +/* Null notification state. */
13.41 +
13.42 +static ObjectNotificationState _null_state;
13.43 +
13.44 +
13.45 +
13.46 +/* Lock protecting per-task notifier access. */
13.47 +
13.48 +static std::mutex _lock;
13.49 +
13.50 +/* Per-task storage for specific waiting operations. */
13.51 +
13.52 +static SpecificObjectNotifier *_notifier = NULL;
13.53 +
13.54 +
13.55 +
13.56 +/* Return the per-task notifier for object-specific waiting operations. */
13.57 +
13.58 +SpecificObjectNotifier *notifier_get_task_notifier()
13.59 +{
13.60 + std::lock_guard<std::mutex> guard(_lock);
13.61 +
13.62 + /* Start any new notifier. */
13.63 +
13.64 + if (_notifier == NULL)
13.65 + {
13.66 + _notifier = new SpecificObjectNotifier;
13.67 + _notifier->start();
13.68 + }
13.69 +
13.70 + return _notifier;
13.71 +}
13.72 +
13.73 +/* Return a local notifier for general object waiting operations. */
13.74 +
13.75 +GeneralObjectNotifier *notifier_get_local_notifier()
13.76 +{
13.77 + GeneralObjectNotifier *notifier = new GeneralObjectNotifier;
13.78 +
13.79 + notifier->start();
13.80 + return notifier;
13.81 +}
13.82 +
13.83 +
13.84 +
13.85 +/* Invoke the mainloop in a thread. */
13.86 +
13.87 +static void *notifier_mainloop(void *data)
13.88 +{
13.89 + ObjectNotifier *notifier = reinterpret_cast<ObjectNotifier *>(data);
13.90 +
13.91 + notifier->mainloop();
13.92 + return 0;
13.93 +}
13.94 +
13.95 +
13.96 +
13.97 +/* Virtual destructor required for base class instance reference deletion. */
13.98 +
13.99 +ObjectNotifier::~ObjectNotifier()
13.100 +{
13.101 +}
13.102 +
13.103 +/* Listen for notifications. */
13.104 +
13.105 +void ObjectNotifier::mainloop()
13.106 +{
13.107 + ipc_message_t msg;
13.108 + l4_umword_t label;
13.109 +
13.110 + while (1)
13.111 + {
13.112 + ipc_message_wait(&msg, &label);
13.113 +
13.114 + /* Clear lower label bits. */
13.115 +
13.116 + label = label & ~3UL;
13.117 +
13.118 + /* Ignore erroneous messages. */
13.119 +
13.120 + if (l4_ipc_error(msg.tag, l4_utcb()))
13.121 + continue;
13.122 +
13.123 + /* Interpret gate labels as notifiable objects. */
13.124 +
13.125 + notifiable_t *object = (notifiable_t *) label;
13.126 +
13.127 + /* Obtain message details. */
13.128 +
13.129 + ipc_message_open(&msg);
13.130 +
13.131 + struct in_words_Notifier_notify *in_words = (struct in_words_Notifier_notify *) ipc_message_get_word_address(&msg, 0);
13.132 +
13.133 + /* Reply to notifications. */
13.134 +
13.135 + ipc_message_reply(&msg);
13.136 + ipc_message_discard(&msg);
13.137 +
13.138 + /* Register the notification. */
13.139 +
13.140 + _notify(object, in_words->flags, in_words->values);
13.141 + }
13.142 +
13.143 + ipc_message_free(&msg);
13.144 +}
13.145 +
13.146 +/* Start listening for notifications. */
13.147 +
13.148 +long ObjectNotifier::start()
13.149 +{
13.150 + if (_started)
13.151 + return L4_EOK;
13.152 +
13.153 + pthread_t thread;
13.154 + pthread_attr_t attr;
13.155 + long err;
13.156 +
13.157 + pthread_attr_init(&attr);
13.158 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13.159 +
13.160 + err = pthread_create(&thread, &attr, notifier_mainloop, this);
13.161 + if (err)
13.162 + return err;
13.163 +
13.164 + _thread = pthread_l4_cap(thread);
13.165 + _started = true;
13.166 +
13.167 + return L4_EOK;
13.168 +}
13.169 +
13.170 +
13.171 +
13.172 +/* Return notification state for the given object or null state if no record
13.173 + existed for the object. */
13.174 +
13.175 +ObjectNotificationState &ObjectNotifier::object_state(notifiable_t *object, bool create)
13.176 +{
13.177 + ObjectNotificationStates::iterator it = _state.find(object);
13.178 +
13.179 + if (it == _state.end())
13.180 + {
13.181 + if (create)
13.182 + return _state[object];
13.183 + else
13.184 + return _null_state;
13.185 + }
13.186 +
13.187 + return it->second;
13.188 +}
13.189 +
13.190 +/* Subscribe to notification events on an object. */
13.191 +
13.192 +long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
13.193 +{
13.194 + l4_cap_idx_t endpoint;
13.195 + long err = get_endpoint(object, &endpoint, true);
13.196 +
13.197 + if (err)
13.198 + return err;
13.199 +
13.200 + /* Subscribe, sending the notification endpoint via the principal reference
13.201 + for the object. */
13.202 +
13.203 + client_Notification notify(object->base->ref);
13.204 +
13.205 + return notify.subscribe(endpoint, flags);
13.206 +}
13.207 +
13.208 +/* Unsubscribe from notification events on an object. */
13.209 +
13.210 +long ObjectNotifier::unsubscribe(notifiable_t *object)
13.211 +{
13.212 + l4_cap_idx_t endpoint;
13.213 + long err = get_endpoint(object, &endpoint, false);
13.214 +
13.215 + if (err)
13.216 + return err;
13.217 +
13.218 + /* Unsubscribe via the notification interface. */
13.219 +
13.220 + client_Notification notify(object->base->ref);
13.221 +
13.222 + notify.unsubscribe(endpoint);
13.223 +
13.224 + return remove_endpoint(object, endpoint);
13.225 +}
13.226 +
13.227 +/* Obtain a notification endpoint for an object. */
13.228 +
13.229 +long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create)
13.230 +{
13.231 + /* Acquire the lock for state lookup. */
13.232 +
13.233 + std::unique_lock<std::mutex> state_guard(_state_lock);
13.234 +
13.235 + ObjectNotificationState &state = object_state(object, create);
13.236 +
13.237 + /* Create a notification endpoint, if necessary. */
13.238 +
13.239 + if (state.is_null())
13.240 + {
13.241 + if (create)
13.242 + {
13.243 + long err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
13.244 +
13.245 + if (err)
13.246 + return err;
13.247 + }
13.248 + else
13.249 + return -L4_ENOENT;
13.250 + }
13.251 +
13.252 + *endpoint = state.endpoint;
13.253 + return L4_EOK;
13.254 +}
13.255 +
13.256 +/* Remove a notification endpoint for an object. */
13.257 +
13.258 +long ObjectNotifier::remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint)
13.259 +{
13.260 + if (l4_is_invalid_cap(endpoint))
13.261 + return -L4_EINVAL;
13.262 +
13.263 + ipc_cap_free_um(endpoint);
13.264 +
13.265 + _state.erase(object);
13.266 +
13.267 + /* Remove the lock for updating object state. */
13.268 +
13.269 + _object_locks.erase(object);
13.270 +
13.271 + return L4_EOK;
13.272 +}
13.273 +
13.274 +
13.275 +
13.276 +/* Handle a notification event for an object. Ideally, this would be invoked by
13.277 + the generic server dispatch mechanism, with the gate label being interpreted
13.278 + and provided as the first parameter. */
13.279 +
13.280 +void GeneralObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
13.281 + notify_values_t values)
13.282 +{
13.283 + /* Enter critical section for the notifier (affecting all objects). */
13.284 +
13.285 + std::unique_lock<std::mutex> general_guard(_general_lock);
13.286 +
13.287 + /* Acquire the lock for state lookup. */
13.288 +
13.289 + std::unique_lock<std::mutex> state_guard(_state_lock);
13.290 +
13.291 + ObjectNotificationState &state = object_state(object, false);
13.292 +
13.293 + if (state.is_null())
13.294 + return;
13.295 +
13.296 + /* Acquire the lock for the object state itself. */
13.297 +
13.298 + std::unique_lock<std::mutex> object_guard(state.lock);
13.299 +
13.300 + /* Record flags and note previous flags. */
13.301 +
13.302 + notify_flags_t recorded = state.pending_notifications;
13.303 +
13.304 + state.pending_notifications |= flags;
13.305 + state.pending_values = values;
13.306 +
13.307 + /* Add an object queue entry for any objects without previous notifications. */
13.308 +
13.309 + if (!recorded)
13.310 + _affected.push_back(object);
13.311 +
13.312 + /* Notify any waiting caller. */
13.313 +
13.314 + _general_condition.notify_one();
13.315 +}
13.316 +
13.317 +void SpecificObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
13.318 + notify_values_t values)
13.319 +{
13.320 + /* Acquire the lock for state lookup. */
13.321 +
13.322 + std::unique_lock<std::mutex> state_guard(_state_lock);
13.323 +
13.324 + ObjectNotificationState &state = object_state(object, false);
13.325 +
13.326 + if (state.is_null())
13.327 + return;
13.328 +
13.329 + /* Acquire the lock for the object state itself. */
13.330 +
13.331 + std::unique_lock<std::mutex> object_guard(state.lock);
13.332 +
13.333 + state.pending_notifications |= flags;
13.334 + state.pending_values = values;
13.335 +
13.336 + /* Notify any waiting caller. */
13.337 +
13.338 + state.condition.notify_one();
13.339 +}
13.340 +
13.341 +
13.342 +
13.343 +/* Transfer pending notifications to the given object. This must be called with
13.344 + a lock acquired on the object notification state. */
13.345 +
13.346 +bool ObjectNotifier::_transfer(ObjectNotificationState &state, notifiable_t *object)
13.347 +{
13.348 + notify_flags_t recorded = state.pending_notifications;
13.349 +
13.350 + if (recorded)
13.351 + {
13.352 + object->notifications = recorded;
13.353 + object->values = state.pending_values;
13.354 + state.pending_notifications = 0;
13.355 + return true;
13.356 + }
13.357 +
13.358 + return false;
13.359 +}
13.360 +
13.361 +
13.362 +
13.363 +/* Obtain object state and transfer notifications. */
13.364 +
13.365 +bool GeneralObjectNotifier::_retrieve_for_object(notifiable_t *object)
13.366 +{
13.367 + /* Acquire the lock for state lookup. */
13.368 +
13.369 + std::unique_lock<std::mutex> state_guard(_state_lock);
13.370 +
13.371 + ObjectNotificationState &state = object_state(object, false);
13.372 +
13.373 + if (state.is_null())
13.374 + return false;
13.375 +
13.376 + /* Acquire the lock for the object state itself, then release the state lock. */
13.377 +
13.378 + std::unique_lock<std::mutex> object_guard(state.lock);
13.379 +
13.380 + state_guard.unlock();
13.381 +
13.382 + /* Call generic method to transfer notifications, if possible. */
13.383 +
13.384 + return _transfer(state, object);
13.385 +}
13.386 +
13.387 +/* Obtain queued objects until one is found that still has events recorded for
13.388 + it. This must be called with the notifier's general lock acquired. */
13.389 +
13.390 +bool GeneralObjectNotifier::_retrieve(notifiable_t **object)
13.391 +{
13.392 + while (!_affected.empty())
13.393 + {
13.394 + *object = _affected.front();
13.395 + _affected.pop_front();
13.396 +
13.397 + if (_retrieve_for_object(*object))
13.398 + return true;
13.399 + }
13.400 +
13.401 + return false;
13.402 +}
13.403 +
13.404 +
13.405 +
13.406 +/* Wait for notification events on objects. */
13.407 +
13.408 +long GeneralObjectNotifier::wait(notifiable_t **object)
13.409 +{
13.410 + std::unique_lock<std::mutex> general_guard(_general_lock);
13.411 +
13.412 + while (1)
13.413 + {
13.414 + /* With pending notifications, update the first object and exit. */
13.415 +
13.416 + if (_retrieve(object))
13.417 + break;
13.418 +
13.419 + /* Otherwise, wait for notifications. */
13.420 +
13.421 + _general_condition.wait(general_guard);
13.422 + }
13.423 +
13.424 + return L4_EOK;
13.425 +}
13.426 +
13.427 +/* Wait for notifications from a single object. */
13.428 +
13.429 +long SpecificObjectNotifier::wait_object(notifiable_t *object)
13.430 +{
13.431 + /* Acquire the lock for reading object state. */
13.432 +
13.433 + std::unique_lock<std::mutex> state_guard(_state_lock);
13.434 +
13.435 + ObjectNotificationState &state = object_state(object, false);
13.436 +
13.437 + if (state.is_null())
13.438 + return -L4_EINVAL;
13.439 +
13.440 + /* Acquire the lock for the object state itself, then release the state lock. */
13.441 +
13.442 + std::unique_lock<std::mutex> object_guard(state.lock);
13.443 +
13.444 + state_guard.unlock();
13.445 +
13.446 + while (1)
13.447 + {
13.448 + /* With pending notifications, update the object and exit. */
13.449 +
13.450 + if (_transfer(state, object))
13.451 + break;
13.452 +
13.453 + /* Otherwise, wait for notifications. */
13.454 +
13.455 + state.condition.wait(object_guard);
13.456 + }
13.457 +
13.458 + return L4_EOK;
13.459 +}
13.460 +
13.461 +// vim: tabstop=2 expandtab shiftwidth=2