L4Re/departure

Changeset

531:79bb98c3403b
2023-03-20 Paul Boddie raw files shortlog changelog graph Moved notifier support into its own library.
libfsclient/Control (file) libfsclient/include/fsclient/notifier.h libfsclient/lib/src/Makefile (file) libfsclient/lib/src/file.cc (file) libfsclient/lib/src/notifier.cc libfsclient/lib/src/process.cc (file) libnotifier/Control (file) libnotifier/Makefile (file) libnotifier/include/Makefile (file) libnotifier/include/notifier/notifier.h (file) libnotifier/lib/Makefile (file) libnotifier/lib/src/Makefile (file) libnotifier/lib/src/notifier.cc (file)
     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