1.1 --- a/libfsclient/include/fsclient/client.h Sat Aug 21 19:28:08 2021 +0200
1.2 +++ b/libfsclient/include/fsclient/client.h Sun Aug 22 22:37:55 2021 +0200
1.3 @@ -72,10 +72,17 @@
1.4 /* Notification operations. */
1.5
1.6 long client_set_blocking(file_t *file, notify_flags_t flags);
1.7 -long client_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type);
1.8 -long client_unsubscribe(file_t *file, notifier_t notifier_type);
1.9 -long client_wait_file(file_t *file);
1.10 -long client_wait_files(file_t **file);
1.11 +
1.12 +/* More advanced notification operations. */
1.13 +
1.14 +void client_notifier_close(file_notifier_t *notifier);
1.15 +file_notifier_t *client_notifier_local(void);
1.16 +file_notifier_t *client_notifier_task(void);
1.17 +
1.18 +long client_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier);
1.19 +long client_unsubscribe(file_t *file, file_notifier_t *notifier);
1.20 +long client_wait_file(file_t *file, file_notifier_t *notifier);
1.21 +long client_wait_files(file_t **file, file_notifier_t *notifier);
1.22
1.23 EXTERN_C_END
1.24
2.1 --- a/libfsclient/include/fsclient/file.h Sat Aug 21 19:28:08 2021 +0200
2.2 +++ b/libfsclient/include/fsclient/file.h Sun Aug 22 22:37:55 2021 +0200
2.3 @@ -28,6 +28,14 @@
2.4
2.5
2.6
2.7 +/* C compatibility types (defined in the implementation). */
2.8 +
2.9 +struct file_notifier;
2.10 +
2.11 +typedef struct file_notifier file_notifier_t;
2.12 +
2.13 +
2.14 +
2.15 EXTERN_C_BEGIN
2.16
2.17 /* File access abstraction. */
2.18 @@ -68,17 +76,6 @@
2.19
2.20
2.21
2.22 -/* Notifier types. */
2.23 -
2.24 -typedef enum
2.25 -{
2.26 - NOTIFIER_TASK = 0,
2.27 - NOTIFIER_THREAD = 1,
2.28 -
2.29 -} notifier_t;
2.30 -
2.31 -
2.32 -
2.33 /* Filesystem operations. */
2.34
2.35 long file_open_for_user(user_t user, l4_cap_idx_t server, l4_cap_idx_t *opener);
2.36 @@ -125,10 +122,14 @@
2.37
2.38 /* Notification functions. */
2.39
2.40 -long file_notify_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type);
2.41 -long file_notify_unsubscribe(file_t *file, notifier_t notifier_type);
2.42 -long file_notify_wait_file(file_t *file);
2.43 -long file_notify_wait_files(file_t **file);
2.44 +void file_notify_close(file_notifier_t *notifier);
2.45 +file_notifier_t *file_notify_local(void);
2.46 +file_notifier_t *file_notify_task(void);
2.47 +
2.48 +long file_notify_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier);
2.49 +long file_notify_unsubscribe(file_t *file, file_notifier_t *notifier);
2.50 +long file_notify_wait_file(file_t *file, file_notifier_t *notifier);
2.51 +long file_notify_wait_files(file_t **file, file_notifier_t *notifier);
2.52
2.53
2.54
3.1 --- a/libfsclient/include/fsclient/notifier.h Sat Aug 21 19:28:08 2021 +0200
3.2 +++ b/libfsclient/include/fsclient/notifier.h Sun Aug 22 22:37:55 2021 +0200
3.3 @@ -96,6 +96,8 @@
3.4 virtual void _unsubscribe(FileNotificationState &state, file_t *file);
3.5
3.6 public:
3.7 + virtual ~FileNotifier();
3.8 +
3.9 /* Local operations. */
3.10
3.11 virtual long start();
3.12 @@ -160,10 +162,8 @@
3.13
3.14 /* Helper functions. */
3.15
3.16 -FileNotifier *get_notifier(notifier_t notifier_type);
3.17 +SpecificFileNotifier *notifier_get_task_notifier();
3.18
3.19 -SpecificFileNotifier *get_task_notifier();
3.20 -
3.21 -GeneralFileNotifier *get_thread_notifier();
3.22 +GeneralFileNotifier *notifier_get_local_notifier();
3.23
3.24 // vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libfsclient/lib/src/client.cc Sat Aug 21 19:28:08 2021 +0200
4.2 +++ b/libfsclient/lib/src/client.cc Sun Aug 22 22:37:55 2021 +0200
4.3 @@ -138,7 +138,7 @@
4.4
4.5 /* Handle an inability to access by blocking, exiting if waiting failed. */
4.6
4.7 - if (client_wait_file(file))
4.8 + if (client_wait_file(file, client_notifier_task()))
4.9 return 0;
4.10 }
4.11
4.12 @@ -369,6 +369,29 @@
4.13
4.14
4.15
4.16 +/* Close a notifier object. */
4.17 +
4.18 +void client_notifier_close(file_notifier_t *notifier)
4.19 +{
4.20 + file_notify_close(notifier);
4.21 +}
4.22 +
4.23 +/* Obtain a local notifier object. */
4.24 +
4.25 +file_notifier_t *client_notifier_local()
4.26 +{
4.27 + return file_notify_local();
4.28 +}
4.29 +
4.30 +/* Obtain a task-wide notifier object. */
4.31 +
4.32 +file_notifier_t *client_notifier_task()
4.33 +{
4.34 + return file_notify_task();
4.35 +}
4.36 +
4.37 +
4.38 +
4.39 /* Read a directory entry. This must be freed by the caller after use. */
4.40
4.41 struct dirent *client_readdir(file_t *file)
4.42 @@ -557,10 +580,12 @@
4.43 /* Since blocking access is used with specific file notifications, the
4.44 per-task notifier is used. */
4.45
4.46 + file_notifier_t *notifier = client_notifier_task();
4.47 +
4.48 if (flags)
4.49 - err = client_subscribe(file, flags, NOTIFIER_TASK);
4.50 + err = client_subscribe(file, flags, notifier);
4.51 else
4.52 - err = client_unsubscribe(file, NOTIFIER_TASK);
4.53 + err = client_unsubscribe(file, notifier);
4.54
4.55 if (err)
4.56 return err;
4.57 @@ -573,12 +598,12 @@
4.58
4.59 /* Subscribe from events concerning a file. */
4.60
4.61 -long client_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type)
4.62 +long client_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier)
4.63 {
4.64 if (file == NULL)
4.65 return -L4_EINVAL;
4.66
4.67 - return file_notify_subscribe(file, flags, notifier_type);
4.68 + return file_notify_subscribe(file, flags, notifier);
4.69 }
4.70
4.71
4.72 @@ -597,32 +622,32 @@
4.73
4.74 /* Unsubscribe from events concerning a file. */
4.75
4.76 -long client_unsubscribe(file_t *file, notifier_t notifier_type)
4.77 +long client_unsubscribe(file_t *file, file_notifier_t *notifier)
4.78 {
4.79 if (file == NULL)
4.80 return -L4_EINVAL;
4.81
4.82 - return file_notify_unsubscribe(file, notifier_type);
4.83 + return file_notify_unsubscribe(file, notifier);
4.84 }
4.85
4.86
4.87
4.88 /* Wait for events involving a specific file. */
4.89
4.90 -long client_wait_file(file_t *file)
4.91 +long client_wait_file(file_t *file, file_notifier_t *notifier)
4.92 {
4.93 if (file == NULL)
4.94 return -L4_EINVAL;
4.95
4.96 - return file_notify_wait_file(file);
4.97 + return file_notify_wait_file(file, notifier);
4.98 }
4.99
4.100 /* Wait for events concerning files, referencing a file object if an event is
4.101 delivered. */
4.102
4.103 -long client_wait_files(file_t **file)
4.104 +long client_wait_files(file_t **file, file_notifier_t *notifier)
4.105 {
4.106 - return file_notify_wait_files(file);
4.107 + return file_notify_wait_files(file, notifier);
4.108 }
4.109
4.110
5.1 --- a/libfsclient/lib/src/file.cc Sat Aug 21 19:28:08 2021 +0200
5.2 +++ b/libfsclient/lib/src/file.cc Sun Aug 22 22:37:55 2021 +0200
5.3 @@ -102,7 +102,7 @@
5.4 here. */
5.5
5.6 if (l4_is_valid_cap(file->ref))
5.7 - get_task_notifier()->unsubscribe(file);
5.8 + notifier_get_task_notifier()->unsubscribe(file);
5.9
5.10 if (file->memory != NULL)
5.11 ipc_detach_dataspace(file->memory);
5.12 @@ -386,50 +386,83 @@
5.13
5.14
5.15
5.16 +/* Opaque notifier type for file_notifier_t. */
5.17 +
5.18 +struct file_notifier
5.19 +{
5.20 + FileNotifier *obj;
5.21 +};
5.22 +
5.23 +
5.24 +
5.25 +/* Close a notifier object. */
5.26 +
5.27 +void file_notify_close(file_notifier_t *notifier)
5.28 +{
5.29 + delete notifier->obj;
5.30 + delete notifier;
5.31 +}
5.32 +
5.33 +/* Obtain a local notifier object. */
5.34 +
5.35 +file_notifier_t *file_notify_local()
5.36 +{
5.37 + file_notifier_t *notifier = new file_notifier_t;
5.38 +
5.39 + notifier->obj = notifier_get_local_notifier();
5.40 + return notifier;
5.41 +}
5.42 +
5.43 +/* Obtain the task-wide notifier object. */
5.44 +
5.45 +file_notifier_t *file_notify_task()
5.46 +{
5.47 + file_notifier_t *notifier = new file_notifier_t;
5.48 +
5.49 + notifier->obj = notifier_get_task_notifier();
5.50 + return notifier;
5.51 +}
5.52 +
5.53 /* Subscribe to notification events on a file. */
5.54
5.55 -long file_notify_subscribe(file_t *file, notify_flags_t flags, notifier_t notifier_type)
5.56 +long file_notify_subscribe(file_t *file, notify_flags_t flags, file_notifier_t *notifier)
5.57 {
5.58 - FileNotifier *notifier = get_notifier(notifier_type);
5.59 -
5.60 - return notifier->subscribe(file, flags);
5.61 + return notifier->obj->subscribe(file, flags);
5.62 }
5.63
5.64 /* Unsubscribe from notification events on a file. */
5.65
5.66 -long file_notify_unsubscribe(file_t *file, notifier_t notifier_type)
5.67 +long file_notify_unsubscribe(file_t *file, file_notifier_t *notifier)
5.68 {
5.69 - FileNotifier *notifier = get_notifier(notifier_type);
5.70 -
5.71 - return notifier->unsubscribe(file);
5.72 + return notifier->obj->unsubscribe(file);
5.73 }
5.74
5.75 /* Wait for a notification event on a file. */
5.76
5.77 -long file_notify_wait_file(file_t *file)
5.78 +long file_notify_wait_file(file_t *file, file_notifier_t *notifier)
5.79 {
5.80 - SpecificFileNotifier *notifier = get_task_notifier();
5.81 - long err = notifier->wait_file(file);
5.82 + SpecificFileNotifier *specific_notifier = dynamic_cast<SpecificFileNotifier *>(notifier->obj);
5.83 + long err = specific_notifier->wait_file(file);
5.84
5.85 /* Unsubscribe if a closure notification has been received. */
5.86
5.87 if (!err && (file->notifications & NOTIFY_PEER_CLOSED))
5.88 - file_notify_unsubscribe(file, NOTIFIER_TASK);
5.89 + file_notify_unsubscribe(file, notifier);
5.90
5.91 return err;
5.92 }
5.93
5.94 /* Wait for notification events on files. */
5.95
5.96 -long file_notify_wait_files(file_t **file)
5.97 +long file_notify_wait_files(file_t **file, file_notifier_t *notifier)
5.98 {
5.99 - GeneralFileNotifier *notifier = get_thread_notifier();
5.100 - long err = notifier->wait(file);
5.101 + GeneralFileNotifier *general_notifier = dynamic_cast<GeneralFileNotifier *>(notifier->obj);
5.102 + long err = general_notifier->wait(file);
5.103
5.104 /* Unsubscribe if a closure notification has been received. */
5.105
5.106 if (!err && ((*file)->notifications & NOTIFY_PEER_CLOSED))
5.107 - file_notify_unsubscribe(*file, NOTIFIER_THREAD);
5.108 + file_notify_unsubscribe(*file, notifier);
5.109
5.110 return err;
5.111 }
6.1 --- a/libfsclient/lib/src/notifier.cc Sat Aug 21 19:28:08 2021 +0200
6.2 +++ b/libfsclient/lib/src/notifier.cc Sun Aug 22 22:37:55 2021 +0200
6.3 @@ -47,17 +47,11 @@
6.4
6.5 static SpecificFileNotifier *_notifier = NULL;
6.6
6.7 -/* Per-thread storage for "open" waiting operations.
6.8 - (This workaround for thread-local storage maps thread capabilities to
6.9 - notifiers). */
6.10 -
6.11 -static std::map<l4_cap_idx_t, GeneralFileNotifier *> _notifiers;
6.12 -
6.13
6.14
6.15 /* Return the per-task notifier for file-specific waiting operations. */
6.16
6.17 -SpecificFileNotifier *get_task_notifier()
6.18 +SpecificFileNotifier *notifier_get_task_notifier()
6.19 {
6.20 std::lock_guard<std::mutex> guard(_lock);
6.21
6.22 @@ -72,37 +66,14 @@
6.23 return _notifier;
6.24 }
6.25
6.26 -/* Return the per-thread notifier for general file waiting operations. */
6.27 -
6.28 -GeneralFileNotifier *get_thread_notifier()
6.29 -{
6.30 - std::lock_guard<std::mutex> guard(_lock);
6.31 -
6.32 - l4_cap_idx_t thread = pthread_l4_cap(pthread_self());
6.33 - GeneralFileNotifier *notifier = _notifiers[thread];
6.34 -
6.35 - /* Start any new notifier. */
6.36 +/* Return a local notifier for general file waiting operations. */
6.37
6.38 - if (notifier == NULL)
6.39 - {
6.40 - notifier = new GeneralFileNotifier;
6.41 - _notifiers[thread] = notifier;
6.42 - notifier->start();
6.43 - }
6.44 -
6.45 - return notifier;
6.46 -}
6.47 +GeneralFileNotifier *notifier_get_local_notifier()
6.48 +{
6.49 + GeneralFileNotifier *notifier = new GeneralFileNotifier;
6.50
6.51 -/* Helper function to obtain the appropriate notifier. */
6.52 -
6.53 -FileNotifier *get_notifier(notifier_t notifier_type)
6.54 -{
6.55 - switch (notifier_type)
6.56 - {
6.57 - case NOTIFIER_TASK: return get_task_notifier();
6.58 - case NOTIFIER_THREAD: return get_thread_notifier();
6.59 - default: return NULL;
6.60 - }
6.61 + notifier->start();
6.62 + return notifier;
6.63 }
6.64
6.65
6.66 @@ -117,6 +88,14 @@
6.67 return 0;
6.68 }
6.69
6.70 +
6.71 +
6.72 +/* Virtual destructor required for base class instance reference deletion. */
6.73 +
6.74 +FileNotifier::~FileNotifier()
6.75 +{
6.76 +}
6.77 +
6.78 /* Listen for notifications. */
6.79
6.80 void FileNotifier::mainloop()
7.1 --- a/tests/dstest_file_client.cc Sat Aug 21 19:28:08 2021 +0200
7.2 +++ b/tests/dstest_file_client.cc Sun Aug 22 22:37:55 2021 +0200
7.3 @@ -61,7 +61,7 @@
7.4
7.5 /* Register for notifications. */
7.6
7.7 - if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_TASK)))
7.8 + if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, client_notifier_task())))
7.9 {
7.10 printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
7.11 return;
7.12 @@ -85,7 +85,7 @@
7.13
7.14 /* Wait for notification of content. */
7.15
7.16 - err = client_wait_file(file);
7.17 + err = client_wait_file(file, client_notifier_task());
7.18
7.19 if (err)
7.20 {
8.1 --- a/tests/dstest_pipe_client.cc Sat Aug 21 19:28:08 2021 +0200
8.2 +++ b/tests/dstest_pipe_client.cc Sun Aug 22 22:37:55 2021 +0200
8.3 @@ -78,10 +78,14 @@
8.4 long err;
8.5 file_t *reader;
8.6
8.7 + /* Use a local notifier to wait for pipe events. */
8.8 +
8.9 + file_notifier_t *notifier = client_notifier_local();
8.10 +
8.11 /* Register the readers for notification. */
8.12
8.13 - if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_THREAD)) ||
8.14 - (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, NOTIFIER_THREAD)))
8.15 + if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)) ||
8.16 + (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)))
8.17 {
8.18 printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
8.19 return;
8.20 @@ -94,11 +98,12 @@
8.21
8.22 /* Wait for notification of content. */
8.23
8.24 - err = client_wait_files(&reader);
8.25 + err = client_wait_files(&reader, notifier);
8.26
8.27 if (err)
8.28 {
8.29 printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));
8.30 + client_notifier_close(notifier);
8.31 return;
8.32 }
8.33
8.34 @@ -143,6 +148,7 @@
8.35
8.36 client_close(reader1);
8.37 client_close(reader2);
8.38 + client_notifier_close(notifier);
8.39
8.40 printf("Data shown.\n");
8.41 }