# HG changeset patch # User Paul Boddie # Date 1629664675 -7200 # Node ID 40dc1cbd5356a31d28e76a4b8eb3b848c142d5eb # Parent 9205a25c62d617e09c9c524e07b3b21eaeea5b97 Replaced per-thread notifiers with local notifiers, also changing the API to employ explicit notifiers for waiting operations. diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/include/fsclient/client.h --- a/libfsclient/include/fsclient/client.h Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/include/fsclient/client.h Sun Aug 22 22:37:55 2021 +0200 @@ -72,10 +72,17 @@ /* Notification operations. */ long client_set_blocking(file_t *file, notify_flags_t flags); -long client_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type); -long client_unsubscribe(file_t *file, notifier_t notifier_type); -long client_wait_file(file_t *file); -long client_wait_files(file_t **file); + +/* More advanced notification operations. */ + +void client_notifier_close(file_notifier_t *notifier); +file_notifier_t *client_notifier_local(void); +file_notifier_t *client_notifier_task(void); + +long client_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier); +long client_unsubscribe(file_t *file, file_notifier_t *notifier); +long client_wait_file(file_t *file, file_notifier_t *notifier); +long client_wait_files(file_t **file, file_notifier_t *notifier); EXTERN_C_END diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/include/fsclient/file.h --- a/libfsclient/include/fsclient/file.h Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/include/fsclient/file.h Sun Aug 22 22:37:55 2021 +0200 @@ -28,6 +28,14 @@ +/* C compatibility types (defined in the implementation). */ + +struct file_notifier; + +typedef struct file_notifier file_notifier_t; + + + EXTERN_C_BEGIN /* File access abstraction. */ @@ -68,17 +76,6 @@ -/* Notifier types. */ - -typedef enum -{ - NOTIFIER_TASK = 0, - NOTIFIER_THREAD = 1, - -} notifier_t; - - - /* Filesystem operations. */ long file_open_for_user(user_t user, l4_cap_idx_t server, l4_cap_idx_t *opener); @@ -125,10 +122,14 @@ /* Notification functions. */ -long file_notify_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type); -long file_notify_unsubscribe(file_t *file, notifier_t notifier_type); -long file_notify_wait_file(file_t *file); -long file_notify_wait_files(file_t **file); +void file_notify_close(file_notifier_t *notifier); +file_notifier_t *file_notify_local(void); +file_notifier_t *file_notify_task(void); + +long file_notify_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier); +long file_notify_unsubscribe(file_t *file, file_notifier_t *notifier); +long file_notify_wait_file(file_t *file, file_notifier_t *notifier); +long file_notify_wait_files(file_t **file, file_notifier_t *notifier); diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/include/fsclient/notifier.h --- a/libfsclient/include/fsclient/notifier.h Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/include/fsclient/notifier.h Sun Aug 22 22:37:55 2021 +0200 @@ -96,6 +96,8 @@ virtual void _unsubscribe(FileNotificationState &state, file_t *file); public: + virtual ~FileNotifier(); + /* Local operations. */ virtual long start(); @@ -160,10 +162,8 @@ /* Helper functions. */ -FileNotifier *get_notifier(notifier_t notifier_type); +SpecificFileNotifier *notifier_get_task_notifier(); -SpecificFileNotifier *get_task_notifier(); - -GeneralFileNotifier *get_thread_notifier(); +GeneralFileNotifier *notifier_get_local_notifier(); // vim: tabstop=4 expandtab shiftwidth=4 diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/lib/src/client.cc --- a/libfsclient/lib/src/client.cc Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/lib/src/client.cc Sun Aug 22 22:37:55 2021 +0200 @@ -138,7 +138,7 @@ /* Handle an inability to access by blocking, exiting if waiting failed. */ - if (client_wait_file(file)) + if (client_wait_file(file, client_notifier_task())) return 0; } @@ -369,6 +369,29 @@ +/* Close a notifier object. */ + +void client_notifier_close(file_notifier_t *notifier) +{ + file_notify_close(notifier); +} + +/* Obtain a local notifier object. */ + +file_notifier_t *client_notifier_local() +{ + return file_notify_local(); +} + +/* Obtain a task-wide notifier object. */ + +file_notifier_t *client_notifier_task() +{ + return file_notify_task(); +} + + + /* Read a directory entry. This must be freed by the caller after use. */ struct dirent *client_readdir(file_t *file) @@ -557,10 +580,12 @@ /* Since blocking access is used with specific file notifications, the per-task notifier is used. */ + file_notifier_t *notifier = client_notifier_task(); + if (flags) - err = client_subscribe(file, flags, NOTIFIER_TASK); + err = client_subscribe(file, flags, notifier); else - err = client_unsubscribe(file, NOTIFIER_TASK); + err = client_unsubscribe(file, notifier); if (err) return err; @@ -573,12 +598,12 @@ /* Subscribe from events concerning a file. */ -long client_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type) +long client_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier) { if (file == NULL) return -L4_EINVAL; - return file_notify_subscribe(file, flags, notifier_type); + return file_notify_subscribe(file, flags, notifier); } @@ -597,32 +622,32 @@ /* Unsubscribe from events concerning a file. */ -long client_unsubscribe(file_t *file, notifier_t notifier_type) +long client_unsubscribe(file_t *file, file_notifier_t *notifier) { if (file == NULL) return -L4_EINVAL; - return file_notify_unsubscribe(file, notifier_type); + return file_notify_unsubscribe(file, notifier); } /* Wait for events involving a specific file. */ -long client_wait_file(file_t *file) +long client_wait_file(file_t *file, file_notifier_t *notifier) { if (file == NULL) return -L4_EINVAL; - return file_notify_wait_file(file); + return file_notify_wait_file(file, notifier); } /* Wait for events concerning files, referencing a file object if an event is delivered. */ -long client_wait_files(file_t **file) +long client_wait_files(file_t **file, file_notifier_t *notifier) { - return file_notify_wait_files(file); + return file_notify_wait_files(file, notifier); } diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/lib/src/file.cc --- a/libfsclient/lib/src/file.cc Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/lib/src/file.cc Sun Aug 22 22:37:55 2021 +0200 @@ -102,7 +102,7 @@ here. */ if (l4_is_valid_cap(file->ref)) - get_task_notifier()->unsubscribe(file); + notifier_get_task_notifier()->unsubscribe(file); if (file->memory != NULL) ipc_detach_dataspace(file->memory); @@ -386,50 +386,83 @@ +/* Opaque notifier type for file_notifier_t. */ + +struct file_notifier +{ + FileNotifier *obj; +}; + + + +/* Close a notifier object. */ + +void file_notify_close(file_notifier_t *notifier) +{ + delete notifier->obj; + delete notifier; +} + +/* Obtain a local notifier object. */ + +file_notifier_t *file_notify_local() +{ + file_notifier_t *notifier = new file_notifier_t; + + notifier->obj = notifier_get_local_notifier(); + return notifier; +} + +/* Obtain the task-wide notifier object. */ + +file_notifier_t *file_notify_task() +{ + file_notifier_t *notifier = new file_notifier_t; + + notifier->obj = notifier_get_task_notifier(); + return notifier; +} + /* Subscribe to notification events on a file. */ -long file_notify_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type) +long file_notify_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier) { - FileNotifier *notifier = get_notifier(notifier_type); - - return notifier->subscribe(file, flags); + return notifier->obj->subscribe(file, flags); } /* Unsubscribe from notification events on a file. */ -long file_notify_unsubscribe(file_t *file, notifier_t notifier_type) +long file_notify_unsubscribe(file_t *file, file_notifier_t *notifier) { - FileNotifier *notifier = get_notifier(notifier_type); - - return notifier->unsubscribe(file); + return notifier->obj->unsubscribe(file); } /* Wait for a notification event on a file. */ -long file_notify_wait_file(file_t *file) +long file_notify_wait_file(file_t *file, file_notifier_t *notifier) { - SpecificFileNotifier *notifier = get_task_notifier(); - long err = notifier->wait_file(file); + SpecificFileNotifier *specific_notifier = dynamic_cast(notifier->obj); + long err = specific_notifier->wait_file(file); /* Unsubscribe if a closure notification has been received. */ if (!err && (file->notifications & NOTIFY_PEER_CLOSED)) - file_notify_unsubscribe(file, NOTIFIER_TASK); + file_notify_unsubscribe(file, notifier); return err; } /* Wait for notification events on files. */ -long file_notify_wait_files(file_t **file) +long file_notify_wait_files(file_t **file, file_notifier_t *notifier) { - GeneralFileNotifier *notifier = get_thread_notifier(); - long err = notifier->wait(file); + GeneralFileNotifier *general_notifier = dynamic_cast(notifier->obj); + long err = general_notifier->wait(file); /* Unsubscribe if a closure notification has been received. */ if (!err && ((*file)->notifications & NOTIFY_PEER_CLOSED)) - file_notify_unsubscribe(*file, NOTIFIER_THREAD); + file_notify_unsubscribe(*file, notifier); return err; } diff -r 9205a25c62d6 -r 40dc1cbd5356 libfsclient/lib/src/notifier.cc --- a/libfsclient/lib/src/notifier.cc Sat Aug 21 19:28:08 2021 +0200 +++ b/libfsclient/lib/src/notifier.cc Sun Aug 22 22:37:55 2021 +0200 @@ -47,17 +47,11 @@ static SpecificFileNotifier *_notifier = NULL; -/* Per-thread storage for "open" waiting operations. - (This workaround for thread-local storage maps thread capabilities to - notifiers). */ - -static std::map _notifiers; - /* Return the per-task notifier for file-specific waiting operations. */ -SpecificFileNotifier *get_task_notifier() +SpecificFileNotifier *notifier_get_task_notifier() { std::lock_guard guard(_lock); @@ -72,37 +66,14 @@ return _notifier; } -/* Return the per-thread notifier for general file waiting operations. */ - -GeneralFileNotifier *get_thread_notifier() -{ - std::lock_guard guard(_lock); - - l4_cap_idx_t thread = pthread_l4_cap(pthread_self()); - GeneralFileNotifier *notifier = _notifiers[thread]; - - /* Start any new notifier. */ +/* Return a local notifier for general file waiting operations. */ - if (notifier == NULL) - { - notifier = new GeneralFileNotifier; - _notifiers[thread] = notifier; - notifier->start(); - } - - return notifier; -} +GeneralFileNotifier *notifier_get_local_notifier() +{ + GeneralFileNotifier *notifier = new GeneralFileNotifier; -/* Helper function to obtain the appropriate notifier. */ - -FileNotifier *get_notifier(notifier_t notifier_type) -{ - switch (notifier_type) - { - case NOTIFIER_TASK: return get_task_notifier(); - case NOTIFIER_THREAD: return get_thread_notifier(); - default: return NULL; - } + notifier->start(); + return notifier; } @@ -117,6 +88,14 @@ return 0; } + + +/* Virtual destructor required for base class instance reference deletion. */ + +FileNotifier::~FileNotifier() +{ +} + /* Listen for notifications. */ void FileNotifier::mainloop() diff -r 9205a25c62d6 -r 40dc1cbd5356 tests/dstest_file_client.cc --- a/tests/dstest_file_client.cc Sat Aug 21 19:28:08 2021 +0200 +++ b/tests/dstest_file_client.cc Sun Aug 22 22:37:55 2021 +0200 @@ -61,7 +61,7 @@ /* Register for notifications. */ - if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_TASK))) + if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, client_notifier_task()))) { printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err)); return; @@ -85,7 +85,7 @@ /* Wait for notification of content. */ - err = client_wait_file(file); + err = client_wait_file(file, client_notifier_task()); if (err) { diff -r 9205a25c62d6 -r 40dc1cbd5356 tests/dstest_pipe_client.cc --- a/tests/dstest_pipe_client.cc Sat Aug 21 19:28:08 2021 +0200 +++ b/tests/dstest_pipe_client.cc Sun Aug 22 22:37:55 2021 +0200 @@ -78,10 +78,14 @@ long err; file_t *reader; + /* Use a local notifier to wait for pipe events. */ + + file_notifier_t *notifier = client_notifier_local(); + /* Register the readers for notification. */ - if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_THREAD)) || - (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_THREAD))) + if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)) || + (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier))) { printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err)); return; @@ -94,11 +98,12 @@ /* Wait for notification of content. */ - err = client_wait_files(&reader); + err = client_wait_files(&reader, notifier); if (err) { printf("Error waiting for notifications: %s\n", l4sys_errtostr(err)); + client_notifier_close(notifier); return; } @@ -143,6 +148,7 @@ client_close(reader1); client_close(reader2); + client_notifier_close(notifier); printf("Data shown.\n"); }