1.1 --- a/libfsclient/lib/src/notifier.cc Thu Feb 16 23:36:52 2023 +0100
1.2 +++ b/libfsclient/lib/src/notifier.cc Fri Feb 17 18:39:43 2023 +0100
1.3 @@ -1,7 +1,7 @@
1.4 /*
1.5 - * File event notification support.
1.6 + * Generic object event notification support.
1.7 *
1.8 - * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
1.9 + * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
1.10 *
1.11 * This program is free software; you can redistribute it and/or
1.12 * modify it under the terms of the GNU General Public License as
1.13 @@ -35,7 +35,7 @@
1.14
1.15 /* Null notification state. */
1.16
1.17 -static FileNotificationState _null_state;
1.18 +static ObjectNotificationState _null_state;
1.19
1.20
1.21
1.22 @@ -45,13 +45,13 @@
1.23
1.24 /* Per-task storage for specific waiting operations. */
1.25
1.26 -static SpecificFileNotifier *_notifier = NULL;
1.27 +static SpecificObjectNotifier *_notifier = NULL;
1.28
1.29
1.30
1.31 -/* Return the per-task notifier for file-specific waiting operations. */
1.32 +/* Return the per-task notifier for object-specific waiting operations. */
1.33
1.34 -SpecificFileNotifier *notifier_get_task_notifier()
1.35 +SpecificObjectNotifier *notifier_get_task_notifier()
1.36 {
1.37 std::lock_guard<std::mutex> guard(_lock);
1.38
1.39 @@ -59,18 +59,18 @@
1.40
1.41 if (_notifier == NULL)
1.42 {
1.43 - _notifier = new SpecificFileNotifier;
1.44 + _notifier = new SpecificObjectNotifier;
1.45 _notifier->start();
1.46 }
1.47
1.48 return _notifier;
1.49 }
1.50
1.51 -/* Return a local notifier for general file waiting operations. */
1.52 +/* Return a local notifier for general object waiting operations. */
1.53
1.54 -GeneralFileNotifier *notifier_get_local_notifier()
1.55 +GeneralObjectNotifier *notifier_get_local_notifier()
1.56 {
1.57 - GeneralFileNotifier *notifier = new GeneralFileNotifier;
1.58 + GeneralObjectNotifier *notifier = new GeneralObjectNotifier;
1.59
1.60 notifier->start();
1.61 return notifier;
1.62 @@ -82,7 +82,7 @@
1.63
1.64 static void *notifier_mainloop(void *data)
1.65 {
1.66 - FileNotifier *notifier = reinterpret_cast<FileNotifier *>(data);
1.67 + ObjectNotifier *notifier = reinterpret_cast<ObjectNotifier *>(data);
1.68
1.69 notifier->mainloop();
1.70 return 0;
1.71 @@ -92,13 +92,13 @@
1.72
1.73 /* Virtual destructor required for base class instance reference deletion. */
1.74
1.75 -FileNotifier::~FileNotifier()
1.76 +ObjectNotifier::~ObjectNotifier()
1.77 {
1.78 }
1.79
1.80 /* Listen for notifications. */
1.81
1.82 -void FileNotifier::mainloop()
1.83 +void ObjectNotifier::mainloop()
1.84 {
1.85 ipc_message_t msg;
1.86 l4_umword_t label;
1.87 @@ -116,9 +116,9 @@
1.88 if (l4_ipc_error(msg.tag, l4_utcb()))
1.89 continue;
1.90
1.91 - /* Interpret gate labels as file objects. */
1.92 + /* Interpret gate labels as notifiable objects. */
1.93
1.94 - file_t *file = (file_t *) label;
1.95 + notifiable_t *object = (notifiable_t *) label;
1.96
1.97 /* Obtain message details. */
1.98
1.99 @@ -133,7 +133,7 @@
1.100
1.101 /* Register the notification. */
1.102
1.103 - _notify(file, flags);
1.104 + _notify(object, flags);
1.105 }
1.106
1.107 ipc_message_free(&msg);
1.108 @@ -141,7 +141,7 @@
1.109
1.110 /* Start listening for notifications. */
1.111
1.112 -long FileNotifier::start()
1.113 +long ObjectNotifier::start()
1.114 {
1.115 if (_started)
1.116 return L4_EOK;
1.117 @@ -165,17 +165,17 @@
1.118
1.119
1.120
1.121 -/* Return a notification state object for the given file or a null object if no
1.122 - record existed for the file. */
1.123 +/* Return notification state for the given object or null state if no record
1.124 + existed for the object. */
1.125
1.126 -FileNotificationState &FileNotifier::file_state(file_t *file, bool create)
1.127 +ObjectNotificationState &ObjectNotifier::object_state(notifiable_t *object, bool create)
1.128 {
1.129 - FileNotificationStates::iterator it = _state.find(file);
1.130 + ObjectNotificationStates::iterator it = _state.find(object);
1.131
1.132 if (it == _state.end())
1.133 {
1.134 if (create)
1.135 - return _state[file];
1.136 + return _state[object];
1.137 else
1.138 return _null_state;
1.139 }
1.140 @@ -183,22 +183,22 @@
1.141 return it->second;
1.142 }
1.143
1.144 -/* Subscribe to notification events on a file. */
1.145 +/* Subscribe to notification events on an object. */
1.146
1.147 -long FileNotifier::subscribe(file_t *file, notify_flags_t flags)
1.148 +long ObjectNotifier::subscribe(notifiable_t *object, notify_flags_t flags)
1.149 {
1.150 /* Acquire the lock for state lookup. */
1.151
1.152 std::unique_lock<std::mutex> state_guard(_state_lock);
1.153
1.154 - FileNotificationState &state = file_state(file, true);
1.155 + ObjectNotificationState &state = object_state(object, true);
1.156 long err;
1.157
1.158 /* Create a notification endpoint, if necessary. */
1.159
1.160 if (state.is_null())
1.161 {
1.162 - err = ipc_server_new_for_thread(&state.endpoint, file, _thread);
1.163 + err = ipc_server_new_for_thread(&state.endpoint, object, _thread);
1.164
1.165 if (err)
1.166 return err;
1.167 @@ -206,59 +206,59 @@
1.168
1.169 /* Subscribe, sending the notification endpoint. */
1.170
1.171 - client_Notification notify(file->ref);
1.172 + client_Notification notify(object->base->ref);
1.173
1.174 err = notify.subscribe(state.endpoint, flags);
1.175
1.176 if (err)
1.177 {
1.178 ipc_cap_free_um(state.endpoint);
1.179 - _state.erase(file);
1.180 + _state.erase(object);
1.181 return err;
1.182 }
1.183
1.184 return L4_EOK;
1.185 }
1.186
1.187 -/* Unsubscribe from notification events on a file. */
1.188 +/* Unsubscribe from notification events on an object. */
1.189
1.190 -long FileNotifier::unsubscribe(file_t *file)
1.191 +long ObjectNotifier::unsubscribe(notifiable_t *object)
1.192 {
1.193 /* Acquire the lock for state lookup. */
1.194
1.195 std::unique_lock<std::mutex> state_guard(_state_lock);
1.196
1.197 - FileNotificationState &state = file_state(file, false);
1.198 + ObjectNotificationState &state = object_state(object, false);
1.199
1.200 if (state.is_null())
1.201 return -L4_EINVAL;
1.202
1.203 /* Unsubscribe via the notification interface. */
1.204
1.205 - client_Notification notify(file->ref);
1.206 + client_Notification notify(object->base->ref);
1.207
1.208 notify.unsubscribe();
1.209
1.210 ipc_cap_free_um(state.endpoint);
1.211
1.212 - _state.erase(file);
1.213 + _state.erase(object);
1.214
1.215 - /* Remove the lock for updating file state. */
1.216 + /* Remove the lock for updating object state. */
1.217
1.218 - _file_locks.erase(file);
1.219 + _object_locks.erase(object);
1.220
1.221 return L4_EOK;
1.222 }
1.223
1.224
1.225
1.226 -/* Handle a notification event for a file. Ideally, this would be invoked by the
1.227 - generic server dispatch mechanism, with the gate label being interpreted and
1.228 - provided as the first parameter. */
1.229 +/* Handle a notification event for an object. Ideally, this would be invoked by
1.230 + the generic server dispatch mechanism, with the gate label being interpreted
1.231 + and provided as the first parameter. */
1.232
1.233 -void GeneralFileNotifier::_notify(file_t *file, notify_flags_t flags)
1.234 +void GeneralObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags)
1.235 {
1.236 - /* Enter critical section for the notifier (affecting all files). */
1.237 + /* Enter critical section for the notifier (affecting all objects). */
1.238
1.239 std::unique_lock<std::mutex> general_guard(_general_lock);
1.240
1.241 @@ -266,14 +266,14 @@
1.242
1.243 std::unique_lock<std::mutex> state_guard(_state_lock);
1.244
1.245 - FileNotificationState &state = file_state(file, false);
1.246 + ObjectNotificationState &state = object_state(object, false);
1.247
1.248 if (state.is_null())
1.249 return;
1.250
1.251 - /* Acquire the lock for the file state itself. */
1.252 + /* Acquire the lock for the object state itself. */
1.253
1.254 - std::unique_lock<std::mutex> file_guard(state.lock);
1.255 + std::unique_lock<std::mutex> object_guard(state.lock);
1.256
1.257 /* Record flags and return previous flags. */
1.258
1.259 @@ -281,30 +281,30 @@
1.260
1.261 state.pending |= flags;
1.262
1.263 - /* Add a file queue entry for any files without previous notifications. */
1.264 + /* Add an object queue entry for any objects without previous notifications. */
1.265
1.266 if (!recorded)
1.267 - _affected.push_back(file);
1.268 + _affected.push_back(object);
1.269
1.270 /* Notify any waiting caller. */
1.271
1.272 _general_condition.notify_one();
1.273 }
1.274
1.275 -void SpecificFileNotifier::_notify(file_t *file, notify_flags_t flags)
1.276 +void SpecificObjectNotifier::_notify(notifiable_t *object, notify_flags_t flags)
1.277 {
1.278 /* Acquire the lock for state lookup. */
1.279
1.280 std::unique_lock<std::mutex> state_guard(_state_lock);
1.281
1.282 - FileNotificationState &state = file_state(file, false);
1.283 + ObjectNotificationState &state = object_state(object, false);
1.284
1.285 if (state.is_null())
1.286 return;
1.287
1.288 - /* Acquire the lock for the file state itself. */
1.289 + /* Acquire the lock for the object state itself. */
1.290
1.291 - std::unique_lock<std::mutex> file_guard(state.lock);
1.292 + std::unique_lock<std::mutex> object_guard(state.lock);
1.293
1.294 state.pending |= flags;
1.295
1.296 @@ -315,16 +315,16 @@
1.297
1.298
1.299
1.300 -/* Transfer pending notifications to the given file. This must be called with a
1.301 - lock acquired on the file notification state. */
1.302 +/* Transfer pending notifications to the given object. This must be called with
1.303 + a lock acquired on the object notification state. */
1.304
1.305 -bool FileNotifier::_transfer(FileNotificationState &state, file_t *file)
1.306 +bool ObjectNotifier::_transfer(ObjectNotificationState &state, notifiable_t *object)
1.307 {
1.308 notify_flags_t recorded = state.pending;
1.309
1.310 if (recorded)
1.311 {
1.312 - file->notifications = recorded;
1.313 + object->notifications = recorded;
1.314 state.pending = 0;
1.315 return true;
1.316 }
1.317 @@ -334,41 +334,41 @@
1.318
1.319
1.320
1.321 -/* Obtain file state and transfer notifications. */
1.322 +/* Obtain object state and transfer notifications. */
1.323
1.324 -bool GeneralFileNotifier::_retrieve_for_file(file_t *file)
1.325 +bool GeneralObjectNotifier::_retrieve_for_object(notifiable_t *object)
1.326 {
1.327 /* Acquire the lock for state lookup. */
1.328
1.329 std::unique_lock<std::mutex> state_guard(_state_lock);
1.330
1.331 - FileNotificationState &state = file_state(file, false);
1.332 + ObjectNotificationState &state = object_state(object, false);
1.333
1.334 if (state.is_null())
1.335 return false;
1.336
1.337 - /* Acquire the lock for the file state itself, then release the state lock. */
1.338 + /* Acquire the lock for the object state itself, then release the state lock. */
1.339
1.340 - std::unique_lock<std::mutex> file_guard(state.lock);
1.341 + std::unique_lock<std::mutex> object_guard(state.lock);
1.342
1.343 state_guard.unlock();
1.344
1.345 /* Call generic method to transfer notifications, if possible. */
1.346
1.347 - return _transfer(state, file);
1.348 + return _transfer(state, object);
1.349 }
1.350
1.351 -/* Obtain queued files until one is found that still has events recorded for it.
1.352 - This must be called with the notifier's general lock acquired. */
1.353 +/* Obtain queued objects until one is found that still has events recorded for
1.354 + it. This must be called with the notifier's general lock acquired. */
1.355
1.356 -bool GeneralFileNotifier::_retrieve(file_t **file)
1.357 +bool GeneralObjectNotifier::_retrieve(notifiable_t **object)
1.358 {
1.359 while (!_affected.empty())
1.360 {
1.361 - *file = _affected.front();
1.362 + *object = _affected.front();
1.363 _affected.pop_front();
1.364
1.365 - if (_retrieve_for_file(*file))
1.366 + if (_retrieve_for_object(*object))
1.367 return true;
1.368 }
1.369
1.370 @@ -377,17 +377,17 @@
1.371
1.372
1.373
1.374 -/* Wait for notification events on files. */
1.375 +/* Wait for notification events on objects. */
1.376
1.377 -long GeneralFileNotifier::wait(file_t **file)
1.378 +long GeneralObjectNotifier::wait(notifiable_t **object)
1.379 {
1.380 std::unique_lock<std::mutex> general_guard(_general_lock);
1.381
1.382 while (1)
1.383 {
1.384 - /* With pending notifications, update the first file and exit. */
1.385 + /* With pending notifications, update the first object and exit. */
1.386
1.387 - if (_retrieve(file))
1.388 + if (_retrieve(object))
1.389 break;
1.390
1.391 /* Otherwise, wait for notifications. */
1.392 @@ -398,35 +398,35 @@
1.393 return L4_EOK;
1.394 }
1.395
1.396 -/* Wait for notifications from a single file. */
1.397 +/* Wait for notifications from a single object. */
1.398
1.399 -long SpecificFileNotifier::wait_file(file_t *file)
1.400 +long SpecificObjectNotifier::wait_object(notifiable_t *object)
1.401 {
1.402 - /* Acquire the lock for reading file state. */
1.403 + /* Acquire the lock for reading object state. */
1.404
1.405 std::unique_lock<std::mutex> state_guard(_state_lock);
1.406
1.407 - FileNotificationState &state = file_state(file, false);
1.408 + ObjectNotificationState &state = object_state(object, false);
1.409
1.410 if (state.is_null())
1.411 return -L4_EINVAL;
1.412
1.413 - /* Acquire the lock for the file state itself, then release the state lock. */
1.414 + /* Acquire the lock for the object state itself, then release the state lock. */
1.415
1.416 - std::unique_lock<std::mutex> file_guard(state.lock);
1.417 + std::unique_lock<std::mutex> object_guard(state.lock);
1.418
1.419 state_guard.unlock();
1.420
1.421 while (1)
1.422 {
1.423 - /* With pending notifications, update the file and exit. */
1.424 + /* With pending notifications, update the object and exit. */
1.425
1.426 - if (_transfer(state, file))
1.427 + if (_transfer(state, object))
1.428 break;
1.429
1.430 /* Otherwise, wait for notifications. */
1.431
1.432 - state.condition.wait(file_guard);
1.433 + state.condition.wait(object_guard);
1.434 }
1.435
1.436 return L4_EOK;