1.1 --- a/libnotifier/lib/src/notifier.cc Tue Mar 21 19:23:34 2023 +0100
1.2 +++ b/libnotifier/lib/src/notifier.cc Tue Mar 21 21:49:00 2023 +0100
1.3 @@ -22,15 +22,13 @@
1.4 #include <map>
1.5 #include <mutex>
1.6
1.7 +#include <fsserver/resource_server.h>
1.8 #include <ipc/cap_alloc.h>
1.9 #include <ipc/server.h>
1.10
1.11 -#include <pthread.h>
1.12 -#include <pthread-l4.h>
1.13 -
1.14 #include "notification_client.h"
1.15 #include "notifier.h"
1.16 -#include "notifier_interface.h"
1.17 +#include "notifier_server.h"
1.18
1.19
1.20
1.21 @@ -79,66 +77,13 @@
1.22
1.23
1.24
1.25 -/* Invoke the mainloop in a thread. */
1.26 -
1.27 -static void *notifier_mainloop(void *data)
1.28 -{
1.29 - ObjectNotifier *notifier = reinterpret_cast<ObjectNotifier *>(data);
1.30 -
1.31 - notifier->mainloop();
1.32 - return 0;
1.33 -}
1.34 -
1.35 -
1.36 -
1.37 /* Virtual destructor required for base class instance reference deletion. */
1.38
1.39 ObjectNotifier::~ObjectNotifier()
1.40 {
1.41 }
1.42
1.43 -/* Listen for notifications. */
1.44
1.45 -void ObjectNotifier::mainloop()
1.46 -{
1.47 - ipc_message_t msg;
1.48 - l4_umword_t label;
1.49 -
1.50 - while (1)
1.51 - {
1.52 - ipc_message_wait(&msg, &label);
1.53 -
1.54 - /* Clear lower label bits. */
1.55 -
1.56 - label = label & ~3UL;
1.57 -
1.58 - /* Ignore erroneous messages. */
1.59 -
1.60 - if (l4_ipc_error(msg.tag, l4_utcb()))
1.61 - continue;
1.62 -
1.63 - /* Interpret gate labels as notifiable objects. */
1.64 -
1.65 - notifiable_t *object = (notifiable_t *) label;
1.66 -
1.67 - /* Obtain message details. */
1.68 -
1.69 - ipc_message_open(&msg);
1.70 -
1.71 - struct in_words_Notifier_notify *in_words = (struct in_words_Notifier_notify *) ipc_message_get_word_address(&msg, 0);
1.72 -
1.73 - /* Reply to notifications. */
1.74 -
1.75 - ipc_message_reply(&msg);
1.76 - ipc_message_discard(&msg);
1.77 -
1.78 - /* Register the notification. */
1.79 -
1.80 - _notify(object, in_words->flags, in_words->values);
1.81 - }
1.82 -
1.83 - ipc_message_free(&msg);
1.84 -}
1.85
1.86 /* Start listening for notifications. */
1.87
1.88 @@ -147,18 +92,17 @@
1.89 if (_started)
1.90 return L4_EOK;
1.91
1.92 - pthread_t thread;
1.93 - pthread_attr_t attr;
1.94 - long err;
1.95 + /* Create a new thread to serve a "null" resource. This resource is not used
1.96 + for notifications but merely for control purposes. */
1.97
1.98 - pthread_attr_init(&attr);
1.99 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1.100 + NotifierResource *notifier = new NotifierResource;
1.101 + ResourceServer server(notifier);
1.102 + long err = server.start_thread(false);
1.103
1.104 - err = pthread_create(&thread, &attr, notifier_mainloop, this);
1.105 if (err)
1.106 return err;
1.107
1.108 - _thread = pthread_l4_cap(thread);
1.109 + _config = server.config();
1.110 _started = true;
1.111
1.112 return L4_EOK;
1.113 @@ -188,66 +132,56 @@
1.114
1.115 long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
1.116 {
1.117 - l4_cap_idx_t endpoint;
1.118 - long err = get_endpoint(object, &endpoint, true);
1.119 + /* Acquire the lock for state lookup. */
1.120 +
1.121 + std::unique_lock<std::mutex> state_guard(_state_lock);
1.122 +
1.123 + /* Obtain potentially new state for the object. */
1.124 +
1.125 + ObjectNotificationState &state = object_state(object, true);
1.126
1.127 - if (err)
1.128 - return err;
1.129 + if (state.is_null())
1.130 + {
1.131 + /* Serve the new object in the notifier thread. */
1.132 +
1.133 + NotifierResource *resource = new NotifierResource(this, object);
1.134 + ResourceServer server(resource);
1.135 + long err = server.start_in_thread(_config->thread, false);
1.136 +
1.137 + if (err)
1.138 + return err;
1.139 +
1.140 + state.endpoint = server.config()->server;
1.141 + }
1.142
1.143 /* Subscribe, sending the notification endpoint via the principal reference
1.144 for the object. */
1.145
1.146 client_Notification notify(object->base->ref);
1.147
1.148 - return notify.subscribe(endpoint, flags);
1.149 + return notify.subscribe(state.endpoint, flags);
1.150 }
1.151
1.152 /* Unsubscribe from notification events on an object. */
1.153
1.154 long ObjectNotifier::unsubscribe(notifiable_t *object)
1.155 {
1.156 - l4_cap_idx_t endpoint;
1.157 - long err = get_endpoint(object, &endpoint, false);
1.158 + /* Acquire the lock for state lookup. */
1.159 +
1.160 + std::unique_lock<std::mutex> state_guard(_state_lock);
1.161
1.162 - if (err)
1.163 - return err;
1.164 + ObjectNotificationState &state = object_state(object, false);
1.165 +
1.166 + if (state.is_null())
1.167 + return -L4_ENOENT;
1.168
1.169 /* Unsubscribe via the notification interface. */
1.170
1.171 client_Notification notify(object->base->ref);
1.172
1.173 - notify.unsubscribe(endpoint);
1.174 -
1.175 - return remove_endpoint(object, endpoint);
1.176 -}
1.177 -
1.178 -/* Obtain a notification endpoint for an object. */
1.179 -
1.180 -long ObjectNotifier::get_endpoint(notifiable_t *object, l4_cap_idx_t *endpoint, bool create)
1.181 -{
1.182 - /* Acquire the lock for state lookup. */
1.183 -
1.184 - std::unique_lock<std::mutex> state_guard(_state_lock);
1.185 -
1.186 - ObjectNotificationState &state = object_state(object, create);
1.187 + notify.unsubscribe(state.endpoint);
1.188
1.189 - /* Create a notification endpoint, if necessary. */
1.190 -
1.191 - if (state.is_null())
1.192 - {
1.193 - if (create)
1.194 - {
1.195 - long err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
1.196 -
1.197 - if (err)
1.198 - return err;
1.199 - }
1.200 - else
1.201 - return -L4_ENOENT;
1.202 - }
1.203 -
1.204 - *endpoint = state.endpoint;
1.205 - return L4_EOK;
1.206 + return remove_endpoint(object, state.endpoint);
1.207 }
1.208
1.209 /* Remove a notification endpoint for an object. */
1.210 @@ -274,8 +208,8 @@
1.211 the generic server dispatch mechanism, with the gate label being interpreted
1.212 and provided as the first parameter. */
1.213
1.214 -void GeneralObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
1.215 - notify_values_t values)
1.216 +void GeneralObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
1.217 + notify_values_t values)
1.218 {
1.219 /* Enter critical section for the notifier (affecting all objects). */
1.220
1.221 @@ -311,8 +245,8 @@
1.222 _general_condition.notify_one();
1.223 }
1.224
1.225 -void SpecificObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags,
1.226 - notify_values_t values)
1.227 +void SpecificObjectNotifier::notify(notifiable_t *object, notify_flags_t flags,
1.228 + notify_values_t values)
1.229 {
1.230 /* Acquire the lock for state lookup. */
1.231
1.232 @@ -455,4 +389,23 @@
1.233 return L4_EOK;
1.234 }
1.235
1.236 +
1.237 +
1.238 +/* Object-specific resource methods. */
1.239 +
1.240 +ipc_server_default_config_type NotifierResource::config()
1.241 +{
1.242 + return config_Notifier;
1.243 +}
1.244 +
1.245 +/* Register a notification received by an object-specific resource. */
1.246 +
1.247 +long NotifierResource::notify(notify_flags_t flags, notify_values_t values)
1.248 +{
1.249 + if (_notifier != NULL)
1.250 + _notifier->notify(_object, flags, values);
1.251 +
1.252 + return L4_EOK;
1.253 +}
1.254 +
1.255 // vim: tabstop=2 expandtab shiftwidth=2