1.1 --- a/libnotifier/Control Tue Mar 21 19:23:34 2023 +0100
1.2 +++ b/libnotifier/Control Tue Mar 21 21:49:00 2023 +0100
1.3 @@ -1,3 +1,3 @@
1.4 -requires: libstdc++ libc libipc
1.5 +requires: libstdc++ libc libipc libfsserver
1.6 provides: libnotifier
1.7 maintainer: paul@boddie.org.uk
2.1 --- a/libnotifier/include/notifier/notifier.h Tue Mar 21 19:23:34 2023 +0100
2.2 +++ b/libnotifier/include/notifier/notifier.h Tue Mar 21 21:49:00 2023 +0100
2.3 @@ -26,8 +26,11 @@
2.4 #include <map>
2.5 #include <mutex>
2.6
2.7 +#include <fsserver/resource.h>
2.8 #include <systypes/base.h>
2.9
2.10 +#include "notifier_interface.h"
2.11 +
2.12
2.13
2.14 /* Object-specific notification details. */
2.15 @@ -78,9 +81,9 @@
2.16
2.17 ObjectNotificationStates _state;
2.18
2.19 - /* Notifier thread details. */
2.20 + /* Notifier resource details. */
2.21
2.22 - l4_cap_idx_t _thread = L4_INVALID_CAP;
2.23 + ipc_server_config_type *_config = NULL;
2.24 bool _started = false;
2.25
2.26 /* Convenience method to access object state. */
2.27 @@ -89,9 +92,6 @@
2.28
2.29 /* Helper methods. */
2.30
2.31 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.32 - notify_values_t values) = 0;
2.33 -
2.34 virtual bool _transfer(ObjectNotificationState &state, notifiable_t *object);
2.35
2.36 public:
2.37 @@ -105,13 +105,12 @@
2.38
2.39 virtual long unsubscribe(notifiable_t *object);
2.40
2.41 - virtual long get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create);
2.42 -
2.43 virtual long remove_endpoint(notifiable_t *object, l4_cap_idx_t endpoint);
2.44
2.45 - /* Event handling support. */
2.46 + /* Helper methods. */
2.47
2.48 - virtual void mainloop();
2.49 + virtual void notify(notifiable_t *object, notify_flags_t flags,
2.50 + notify_values_t values) = 0;
2.51 };
2.52
2.53
2.54 @@ -136,15 +135,17 @@
2.55
2.56 /* Helper methods. */
2.57
2.58 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.59 - notify_values_t values);
2.60 -
2.61 virtual bool _retrieve(notifiable_t **object);
2.62
2.63 virtual bool _retrieve_for_object(notifiable_t *object);
2.64
2.65 public:
2.66 virtual long wait(notifiable_t **object);
2.67 +
2.68 + /* Helper methods. */
2.69 +
2.70 + virtual void notify(notifiable_t *object, notify_flags_t flags,
2.71 + notify_values_t values);
2.72 };
2.73
2.74
2.75 @@ -153,14 +154,46 @@
2.76
2.77 class SpecificObjectNotifier : public ObjectNotifier
2.78 {
2.79 -protected:
2.80 +public:
2.81 + virtual long wait_object(notifiable_t *object);
2.82 +
2.83 /* Helper methods. */
2.84
2.85 - virtual void _notify(notifiable_t *object, notify_flags_t flags,
2.86 - notify_values_t values);
2.87 + virtual void notify(notifiable_t *object, notify_flags_t flags,
2.88 + notify_values_t values);
2.89 +};
2.90 +
2.91 +
2.92 +
2.93 +/* Object-specific notifier resource. */
2.94 +
2.95 +class NotifierResource : public Notifier, public Resource
2.96 +{
2.97 +protected:
2.98 + ObjectNotifier *_notifier;
2.99 + notifiable_t *_object;
2.100
2.101 public:
2.102 - virtual long wait_object(notifiable_t *object);
2.103 + explicit NotifierResource(ObjectNotifier *notifier, notifiable_t *object)
2.104 + : _notifier(notifier), _object(object)
2.105 + {
2.106 + }
2.107 +
2.108 + explicit NotifierResource()
2.109 + : _notifier(NULL), _object(NULL)
2.110 + {
2.111 + }
2.112 +
2.113 + /* Server details. */
2.114 +
2.115 + virtual ipc_server_default_config_type config();
2.116 +
2.117 + virtual void *interface()
2.118 + { return static_cast<Notifier *>(this); }
2.119 +
2.120 + /* Notifier methods. */
2.121 +
2.122 + virtual long notify(notify_flags_t flags, notify_values_t values);
2.123 };
2.124
2.125
3.1 --- a/libnotifier/lib/src/Makefile Tue Mar 21 19:23:34 2023 +0100
3.2 +++ b/libnotifier/lib/src/Makefile Tue Mar 21 21:49:00 2023 +0100
3.3 @@ -15,21 +15,26 @@
3.4
3.5 # Individual interfaces.
3.6
3.7 -CLIENT_INTERFACES_CC = notifier notification
3.8 +CLIENT_INTERFACES_CC = notification
3.9 +
3.10 +SERVER_INTERFACES_CC = notifier
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 +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC))
3.17 +
3.18 PLAIN_SRC_CC = notifier.cc
3.19
3.20 # Normal definitions.
3.21
3.22 SRC_CC = \
3.23 $(CLIENT_INTERFACES_SRC_CC) \
3.24 + $(SERVER_INTERFACES_SRC_CC) \
3.25 $(PLAIN_SRC_CC)
3.26
3.27 -REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes
3.28 +REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes libfsserver
3.29
3.30 PRIVATE_INCDIR = $(PKGDIR)/include/notifier $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
3.31 CONTRIB_INCDIR = libnotifier
4.1 --- a/libnotifier/lib/src/notifier.cc Tue Mar 21 19:23:34 2023 +0100
4.2 +++ b/libnotifier/lib/src/notifier.cc Tue Mar 21 21:49:00 2023 +0100
4.3 @@ -22,15 +22,13 @@
4.4 #include <map>
4.5 #include <mutex>
4.6
4.7 +#include <fsserver/resource_server.h>
4.8 #include <ipc/cap_alloc.h>
4.9 #include <ipc/server.h>
4.10
4.11 -#include <pthread.h>
4.12 -#include <pthread-l4.h>
4.13 -
4.14 #include "notification_client.h"
4.15 #include "notifier.h"
4.16 -#include "notifier_interface.h"
4.17 +#include "notifier_server.h"
4.18
4.19
4.20
4.21 @@ -79,66 +77,13 @@
4.22
4.23
4.24
4.25 -/* Invoke the mainloop in a thread. */
4.26 -
4.27 -static void *notifier_mainloop(void *data)
4.28 -{
4.29 - ObjectNotifier *notifier = reinterpret_cast<ObjectNotifier *>(data);
4.30 -
4.31 - notifier->mainloop();
4.32 - return 0;
4.33 -}
4.34 -
4.35 -
4.36 -
4.37 /* Virtual destructor required for base class instance reference deletion. */
4.38
4.39 ObjectNotifier::~ObjectNotifier()
4.40 {
4.41 }
4.42
4.43 -/* Listen for notifications. */
4.44
4.45 -void ObjectNotifier::mainloop()
4.46 -{
4.47 - ipc_message_t msg;
4.48 - l4_umword_t label;
4.49 -
4.50 - while (1)
4.51 - {
4.52 - ipc_message_wait(&msg, &label);
4.53 -
4.54 - /* Clear lower label bits. */
4.55 -
4.56 - label = label & ~3UL;
4.57 -
4.58 - /* Ignore erroneous messages. */
4.59 -
4.60 - if (l4_ipc_error(msg.tag, l4_utcb()))
4.61 - continue;
4.62 -
4.63 - /* Interpret gate labels as notifiable objects. */
4.64 -
4.65 - notifiable_t *object = (notifiable_t *) label;
4.66 -
4.67 - /* Obtain message details. */
4.68 -
4.69 - ipc_message_open(&msg);
4.70 -
4.71 - struct in_words_Notifier_notify *in_words = (struct in_words_Notifier_notify *) ipc_message_get_word_address(&msg, 0);
4.72 -
4.73 - /* Reply to notifications. */
4.74 -
4.75 - ipc_message_reply(&msg);
4.76 - ipc_message_discard(&msg);
4.77 -
4.78 - /* Register the notification. */
4.79 -
4.80 - _notify(object, in_words->flags, in_words->values);
4.81 - }
4.82 -
4.83 - ipc_message_free(&msg);
4.84 -}
4.85
4.86 /* Start listening for notifications. */
4.87
4.88 @@ -147,18 +92,17 @@
4.89 if (_started)
4.90 return L4_EOK;
4.91
4.92 - pthread_t thread;
4.93 - pthread_attr_t attr;
4.94 - long err;
4.95 + /* Create a new thread to serve a "null" resource. This resource is not used
4.96 + for notifications but merely for control purposes. */
4.97
4.98 - pthread_attr_init(&attr);
4.99 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4.100 + NotifierResource *notifier = new NotifierResource;
4.101 + ResourceServer server(notifier);
4.102 + long err = server.start_thread(false);
4.103
4.104 - err = pthread_create(&thread, &attr, notifier_mainloop, this);
4.105 if (err)
4.106 return err;
4.107
4.108 - _thread = pthread_l4_cap(thread);
4.109 + _config = server.config();
4.110 _started = true;
4.111
4.112 return L4_EOK;
4.113 @@ -188,66 +132,56 @@
4.114
4.115 long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
4.116 {
4.117 - l4_cap_idx_t endpoint;
4.118 - long err = get_endpoint(object, &endpoint, true);
4.119 + /* Acquire the lock for state lookup. */
4.120 +
4.121 + std::unique_lock<std::mutex> state_guard(_state_lock);
4.122 +
4.123 + /* Obtain potentially new state for the object. */
4.124 +
4.125 + ObjectNotificationState &state = object_state(object, true);
4.126
4.127 - if (err)
4.128 - return err;
4.129 + if (state.is_null())
4.130 + {
4.131 + /* Serve the new object in the notifier thread. */
4.132 +
4.133 + NotifierResource *resource = new NotifierResource(this, object);
4.134 + ResourceServer server(resource);
4.135 + long err = server.start_in_thread(_config->thread, false);
4.136 +
4.137 + if (err)
4.138 + return err;
4.139 +
4.140 + state.endpoint = server.config()->server;
4.141 + }
4.142
4.143 /* Subscribe, sending the notification endpoint via the principal reference
4.144 for the object. */
4.145
4.146 client_Notification notify(object->base->ref);
4.147
4.148 - return notify.subscribe(endpoint, flags);
4.149 + return notify.subscribe(state.endpoint, flags);
4.150 }
4.151
4.152 /* Unsubscribe from notification events on an object. */
4.153
4.154 long ObjectNotifier::unsubscribe(notifiable_t *object)
4.155 {
4.156 - l4_cap_idx_t endpoint;
4.157 - long err = get_endpoint(object, &endpoint, false);
4.158 + /* Acquire the lock for state lookup. */
4.159 +
4.160 + std::unique_lock<std::mutex> state_guard(_state_lock);
4.161
4.162 - if (err)
4.163 - return err;
4.164 + ObjectNotificationState &state = object_state(object, false);
4.165 +
4.166 + if (state.is_null())
4.167 + return -L4_ENOENT;
4.168
4.169 /* Unsubscribe via the notification interface. */
4.170
4.171 client_Notification notify(object->base->ref);
4.172
4.173 - notify.unsubscribe(endpoint);
4.174 -
4.175 - return remove_endpoint(object, endpoint);
4.176 -}
4.177 -
4.178 -/* Obtain a notification endpoint for an object. */
4.179 -
4.180 -long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create)
4.181 -{
4.182 - /* Acquire the lock for state lookup. */
4.183 -
4.184 - std::unique_lock<std::mutex> state_guard(_state_lock);
4.185 -
4.186 - ObjectNotificationState &state = object_state(object, create);
4.187 + notify.unsubscribe(state.endpoint);
4.188
4.189 - /* Create a notification endpoint, if necessary. */
4.190 -
4.191 - if (state.is_null())
4.192 - {
4.193 - if (create)
4.194 - {
4.195 - long err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
4.196 -
4.197 - if (err)
4.198 - return err;
4.199 - }
4.200 - else
4.201 - return -L4_ENOENT;
4.202 - }
4.203 -
4.204 - *endpoint = state.endpoint;
4.205 - return L4_EOK;
4.206 + return remove_endpoint(object, state.endpoint);
4.207 }
4.208
4.209 /* Remove a notification endpoint for an object. */
4.210 @@ -274,8 +208,8 @@
4.211 the generic server dispatch mechanism, with the gate label being interpreted
4.212 and provided as the first parameter. */
4.213
4.214 -void GeneralObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
4.215 - notify_values_t values)
4.216 +void GeneralObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
4.217 + notify_values_t values)
4.218 {
4.219 /* Enter critical section for the notifier (affecting all objects). */
4.220
4.221 @@ -311,8 +245,8 @@
4.222 _general_condition.notify_one();
4.223 }
4.224
4.225 -void SpecificObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
4.226 - notify_values_t values)
4.227 +void SpecificObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
4.228 + notify_values_t values)
4.229 {
4.230 /* Acquire the lock for state lookup. */
4.231
4.232 @@ -455,4 +389,23 @@
4.233 return L4_EOK;
4.234 }
4.235
4.236 +
4.237 +
4.238 +/* Object-specific resource methods. */
4.239 +
4.240 +ipc_server_default_config_type NotifierResource::config()
4.241 +{
4.242 + return config_Notifier;
4.243 +}
4.244 +
4.245 +/* Register a notification received by an object-specific resource. */
4.246 +
4.247 +long NotifierResource::notify(notify_flags_t flags, notify_values_t values)
4.248 +{
4.249 + if (_notifier != NULL)
4.250 + _notifier->notify(_object, flags, values);
4.251 +
4.252 + return L4_EOK;
4.253 +}
4.254 +
4.255 // vim: tabstop=2 expandtab shiftwidth=2