1.1 --- a/libfsclient/include/fsclient/client.h Fri Jul 02 23:53:13 2021 +0200
1.2 +++ b/libfsclient/include/fsclient/client.h Tue Jul 06 00:45:25 2021 +0200
1.3 @@ -59,7 +59,6 @@
1.4 long client_set_blocking(file_t *file, notify_flags_t flags);
1.5 long client_subscribe(file_t *file, notify_flags_t flags);
1.6 long client_unsubscribe(file_t *file);
1.7 -long client_wait_init(file_t *file);
1.8 long client_wait_file(file_t *file);
1.9 long client_wait_files(file_t **file);
1.10
2.1 --- a/libfsclient/include/fsclient/file.h Fri Jul 02 23:53:13 2021 +0200
2.2 +++ b/libfsclient/include/fsclient/file.h Tue Jul 06 00:45:25 2021 +0200
2.3 @@ -37,9 +37,9 @@
2.4
2.5 l4_cap_idx_t ref;
2.6
2.7 - /* Notification IRQ reference. */
2.8 + /* Notification endpoint reference. */
2.9
2.10 - l4_cap_idx_t irq;
2.11 + l4_cap_idx_t notifier;
2.12
2.13 /* Mapped memory accessing a file region. */
2.14
2.15 @@ -67,6 +67,10 @@
2.16
2.17 notify_flags_t can_block;
2.18
2.19 + /* Saved notifications. */
2.20 +
2.21 + notify_flags_t notifications;
2.22 +
2.23 } file_t;
2.24
2.25
2.26 @@ -115,7 +119,6 @@
2.27
2.28 long file_notify_subscribe(file_t *file, notify_flags_t flags);
2.29 long file_notify_unsubscribe(file_t *file);
2.30 -long file_notify_bind_file(file_t *file);
2.31 long file_notify_wait_file(file_t *file);
2.32 long file_notify_wait_files(file_t **file);
2.33
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/libfsclient/include/fsclient/notifier.h Tue Jul 06 00:45:25 2021 +0200
3.3 @@ -0,0 +1,79 @@
3.4 +/*
3.5 + * File event notification support.
3.6 + *
3.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
3.8 + *
3.9 + * This program is free software; you can redistribute it and/or
3.10 + * modify it under the terms of the GNU General Public License as
3.11 + * published by the Free Software Foundation; either version 2 of
3.12 + * the License, or (at your option) any later version.
3.13 + *
3.14 + * This program is distributed in the hope that it will be useful,
3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + * GNU General Public License for more details.
3.18 + *
3.19 + * You should have received a copy of the GNU General Public License
3.20 + * along with this program; if not, write to the Free Software
3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
3.22 + * Boston, MA 02110-1301, USA
3.23 + */
3.24 +
3.25 +#pragma once
3.26 +
3.27 +#include <condition_variable>
3.28 +#include <list>
3.29 +#include <mutex>
3.30 +
3.31 +#include <fsclient/file.h>
3.32 +#include <ipc/server.h>
3.33 +#include <systypes/base.h>
3.34 +
3.35 +
3.36 +
3.37 +/* An object for monitoring file event notifications. */
3.38 +
3.39 +class FileNotifier
3.40 +{
3.41 +protected:
3.42 + std::list<file_t *> _affected;
3.43 + l4_cap_idx_t _thread = L4_INVALID_CAP;
3.44 + bool _started = false;
3.45 +
3.46 + std::mutex _lock;
3.47 + std::condition_variable _notified;
3.48 +
3.49 + /* Helper methods. */
3.50 +
3.51 + virtual void _notify(file_t *file, notify_flags_t flags);
3.52 +
3.53 +public:
3.54 + /* Server details. */
3.55 +
3.56 + int expected_items();
3.57 +
3.58 + ipc_server_handler_type handler();
3.59 +
3.60 + void *interface()
3.61 + { return static_cast<FileNotifier *>(this); }
3.62 +
3.63 + /* Local operations. */
3.64 +
3.65 + virtual long subscribe(file_t *file, notify_flags_t flags);
3.66 +
3.67 + virtual long unsubscribe(file_t *file);
3.68 +
3.69 + virtual void mainloop();
3.70 +
3.71 + virtual long start();
3.72 +
3.73 + virtual long wait(file_t **file);
3.74 +};
3.75 +
3.76 +
3.77 +
3.78 +/* Helper functions. */
3.79 +
3.80 +FileNotifier *get_notifier();
3.81 +
3.82 +// vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libfsclient/lib/src/Makefile Fri Jul 02 23:53:13 2021 +0200
4.2 +++ b/libfsclient/lib/src/Makefile Tue Jul 06 00:45:25 2021 +0200
4.3 @@ -21,7 +21,7 @@
4.4
4.5 CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
4.6
4.7 -PLAIN_SRC_CC = client.cc file.cc
4.8 +PLAIN_SRC_CC = client.cc file.cc notifier.cc
4.9
4.10 # Normal definitions.
4.11
5.1 --- a/libfsclient/lib/src/client.cc Fri Jul 02 23:53:13 2021 +0200
5.2 +++ b/libfsclient/lib/src/client.cc Tue Jul 06 00:45:25 2021 +0200
5.3 @@ -459,23 +459,6 @@
5.4
5.5
5.6
5.7 -/* Bind and initialise files involved with notifications. */
5.8 -
5.9 -long client_wait_init(file_t *file)
5.10 -{
5.11 - if (file == NULL)
5.12 - return -L4_EINVAL;
5.13 -
5.14 - long err = file_notify_bind_file(file);
5.15 -
5.16 - if (err)
5.17 - return err;
5.18 -
5.19 - ipc_init_irq(file->irq);
5.20 -
5.21 - return L4_EOK;
5.22 -}
5.23 -
5.24 /* Wait for events involving a specific file. */
5.25
5.26 long client_wait_file(file_t *file)
6.1 --- a/libfsclient/lib/src/file.cc Fri Jul 02 23:53:13 2021 +0200
6.2 +++ b/libfsclient/lib/src/file.cc Tue Jul 06 00:45:25 2021 +0200
6.3 @@ -21,19 +21,12 @@
6.4
6.5 #include <ipc/cap_alloc.h>
6.6 #include <ipc/mem_ipc.h>
6.7 -#include <ipc/irq.h>
6.8 -
6.9 -#include <l4/sys/irq.h>
6.10 -
6.11 -#include <pthread.h>
6.12 -#include <pthread-l4.h>
6.13
6.14 #include <string.h>
6.15
6.16 #include "dataspace_client.h"
6.17 #include "file_client.h"
6.18 #include "flush_client.h"
6.19 -#include "notification_client.h"
6.20 #include "opener_client.h"
6.21 #include "opener_context_client.h"
6.22 #include "pipe_client.h"
6.23 @@ -41,6 +34,7 @@
6.24 #include "mapped_file_client.h"
6.25
6.26 #include "file.h"
6.27 +#include "notifier.h"
6.28
6.29
6.30
6.31 @@ -73,7 +67,7 @@
6.32 {
6.33 file->memory = NULL;
6.34 file->ref = L4_INVALID_CAP;
6.35 - file->irq = L4_INVALID_CAP;
6.36 + file->notifier = L4_INVALID_CAP;
6.37 file->start_pos = 0;
6.38 file->end_pos = 0;
6.39 file->data_end = 0;
6.40 @@ -81,6 +75,7 @@
6.41 file->can_mmap = 1;
6.42 file->has_size = 1;
6.43 file->can_block = 0;
6.44 + file->notifications = 0;
6.45 }
6.46
6.47
6.48 @@ -92,8 +87,8 @@
6.49 if (l4_is_valid_cap(file->ref))
6.50 ipc_cap_free_um(file->ref);
6.51
6.52 - if (l4_is_valid_cap(file->irq))
6.53 - ipc_cap_free_um(file->irq);
6.54 + if (l4_is_valid_cap(file->notifier))
6.55 + ipc_cap_free_um(file->notifier);
6.56
6.57 if (file->memory != NULL)
6.58 ipc_detach_dataspace(file->memory);
6.59 @@ -378,64 +373,48 @@
6.60
6.61 long file_notify_subscribe(file_t *file, notify_flags_t flags)
6.62 {
6.63 - client_Notification notify(file->ref);
6.64 + FileNotifier *notifier = get_notifier();
6.65
6.66 - return notify.subscribe(flags, &file->irq);
6.67 + return notifier->subscribe(file, flags);
6.68 }
6.69
6.70 /* Unsubscribe from notification events on a file. */
6.71
6.72 long file_notify_unsubscribe(file_t *file)
6.73 {
6.74 - if (l4_is_invalid_cap(file->irq))
6.75 + if (l4_is_invalid_cap(file->notifier))
6.76 return -L4_EINVAL;
6.77
6.78 - l4_irq_detach(file->irq);
6.79 -
6.80 - client_Notification notify(file->ref);
6.81 -
6.82 - return notify.unsubscribe();
6.83 -}
6.84 + FileNotifier *notifier = get_notifier();
6.85
6.86 -/* Bind a file IRQ to the current thread. */
6.87 -
6.88 -long file_notify_bind_file(file_t *file)
6.89 -{
6.90 - if (l4_is_invalid_cap(file->irq))
6.91 - return -L4_EINVAL;
6.92 -
6.93 - return ipc_bind_irq(file->irq, (l4_umword_t) file, pthread_l4_cap(pthread_self()));
6.94 + return notifier->unsubscribe(file);
6.95 }
6.96
6.97 /* Wait for a notification event on a file. */
6.98
6.99 long file_notify_wait_file(file_t *file)
6.100 {
6.101 - long err = file_notify_bind_file(file);
6.102 + file_t *affected;
6.103 +
6.104 + do
6.105 + {
6.106 + long err = file_notify_wait_files(&affected);
6.107
6.108 - if (err)
6.109 - return err;
6.110 + if (err)
6.111 + return err;
6.112 + }
6.113 + while (affected != file);
6.114
6.115 - return l4_error(l4_irq_receive(file->irq, L4_IPC_NEVER));
6.116 + return L4_EOK;
6.117 }
6.118
6.119 /* Wait for notification events on files. */
6.120
6.121 long file_notify_wait_files(file_t **file)
6.122 {
6.123 - l4_umword_t label;
6.124 - l4_msgtag_t tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER);
6.125 - long err = l4_error(tag);
6.126 + FileNotifier *notifier = get_notifier();
6.127
6.128 - if (err)
6.129 - *file = NULL;
6.130 - else
6.131 - {
6.132 - label = label & ~3UL;
6.133 - *file = reinterpret_cast<file_t *>(label);
6.134 - }
6.135 -
6.136 - return err;
6.137 + return notifier->wait(file);
6.138 }
6.139
6.140
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/libfsclient/lib/src/notifier.cc Tue Jul 06 00:45:25 2021 +0200
7.3 @@ -0,0 +1,205 @@
7.4 +/*
7.5 + * File event notification support.
7.6 + *
7.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
7.8 + *
7.9 + * This program is free software; you can redistribute it and/or
7.10 + * modify it under the terms of the GNU General Public License as
7.11 + * published by the Free Software Foundation; either version 2 of
7.12 + * the License, or (at your option) any later version.
7.13 + *
7.14 + * This program is distributed in the hope that it will be useful,
7.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.17 + * GNU General Public License for more details.
7.18 + *
7.19 + * You should have received a copy of the GNU General Public License
7.20 + * along with this program; if not, write to the Free Software
7.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
7.22 + * Boston, MA 02110-1301, USA
7.23 + */
7.24 +
7.25 +#include <map>
7.26 +#include <mutex>
7.27 +
7.28 +#include <ipc/cap_alloc.h>
7.29 +#include <ipc/server.h>
7.30 +
7.31 +#include <pthread.h>
7.32 +#include <pthread-l4.h>
7.33 +
7.34 +#include "notification_client.h"
7.35 +#include "notifier.h"
7.36 +
7.37 +
7.38 +
7.39 +/* Thread-local storage workaround. */
7.40 +
7.41 +static std::mutex lock;
7.42 +static std::map<l4_cap_idx_t, FileNotifier *> notifiers;
7.43 +
7.44 +FileNotifier *get_notifier()
7.45 +{
7.46 + std::lock_guard<std::mutex> guard(lock);
7.47 +
7.48 + l4_cap_idx_t thread = pthread_l4_cap(pthread_self());
7.49 + FileNotifier *notifier = notifiers[thread];
7.50 +
7.51 + /* Start any new notifier. */
7.52 +
7.53 + if (notifier == NULL)
7.54 + {
7.55 + notifier = new FileNotifier;
7.56 + notifiers[thread] = notifier;
7.57 + notifier->start();
7.58 + }
7.59 +
7.60 + return notifier;
7.61 +}
7.62 +
7.63 +
7.64 +
7.65 +/* Subscribe to notification events on a file. */
7.66 +
7.67 +long FileNotifier::subscribe(file_t *file, notify_flags_t flags)
7.68 +{
7.69 + /* Create a notification endpoint, if necessary. */
7.70 +
7.71 + if (l4_is_invalid_cap(file->notifier))
7.72 + {
7.73 + long err = ipc_server_new_for_thread(&file->notifier, file, _thread);
7.74 +
7.75 + if (err)
7.76 + return err;
7.77 + }
7.78 +
7.79 + client_Notification notify(file->ref);
7.80 +
7.81 + return notify.subscribe(file->notifier, flags);
7.82 +}
7.83 +
7.84 +/* Unsubscribe from notification events on a file. */
7.85 +
7.86 +long FileNotifier::unsubscribe(file_t *file)
7.87 +{
7.88 + if (l4_is_invalid_cap(file->notifier))
7.89 + return -L4_EINVAL;
7.90 +
7.91 + ipc_cap_free_um(file->notifier);
7.92 +
7.93 + client_Notification notify(file->ref);
7.94 +
7.95 + return notify.unsubscribe();
7.96 +}
7.97 +
7.98 +/* Handle a notification event for a file. Ideally, this would be invoked by the
7.99 + generic server dispatch mechanism, with the gate label being interpreted and
7.100 + provided as the first parameter. */
7.101 +
7.102 +void FileNotifier::_notify(file_t *file, notify_flags_t flags)
7.103 +{
7.104 + std::unique_lock<std::mutex> guard(_lock);
7.105 +
7.106 + /* Record the flags in the file object. */
7.107 +
7.108 + file->notifications = flags;
7.109 + _affected.push_back(file);
7.110 +
7.111 + /* Notify any waiting caller. */
7.112 +
7.113 + _notified.notify_one();
7.114 +}
7.115 +
7.116 +/* Listen for notifications. */
7.117 +
7.118 +void FileNotifier::mainloop()
7.119 +{
7.120 + ipc_message_t msg;
7.121 + l4_umword_t label;
7.122 +
7.123 + while (1)
7.124 + {
7.125 + ipc_message_wait(&msg, &label);
7.126 +
7.127 + /* Clear lower label bits. */
7.128 +
7.129 + label = label & ~3UL;
7.130 +
7.131 + /* Ignore erroneous messages. */
7.132 +
7.133 + if (l4_ipc_error(msg.tag, l4_utcb()))
7.134 + continue;
7.135 +
7.136 + /* Reply to notifications. */
7.137 +
7.138 + ipc_message_reply(&msg);
7.139 +
7.140 + /* Interpret gate labels as file objects. */
7.141 +
7.142 + file_t *file = (file_t *) label;
7.143 + notify_flags_t flags = ipc_message_get_word(&msg, 0);
7.144 +
7.145 + /* Register the notification. */
7.146 +
7.147 + _notify(file, flags);
7.148 + }
7.149 +
7.150 + ipc_message_free(&msg);
7.151 +}
7.152 +
7.153 +/* Invoke the mainloop in a thread. */
7.154 +
7.155 +static void *notifier_mainloop(void *data)
7.156 +{
7.157 + FileNotifier *notifier = reinterpret_cast<FileNotifier *>(data);
7.158 +
7.159 + notifier->mainloop();
7.160 + return 0;
7.161 +}
7.162 +
7.163 +/* Start listening for notifications. */
7.164 +
7.165 +long FileNotifier::start()
7.166 +{
7.167 + if (_started)
7.168 + return L4_EOK;
7.169 +
7.170 + pthread_t thread;
7.171 + pthread_attr_t attr;
7.172 + long err;
7.173 +
7.174 + pthread_attr_init(&attr);
7.175 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
7.176 +
7.177 + err = pthread_create(&thread, &attr, notifier_mainloop, this);
7.178 + if (err)
7.179 + return err;
7.180 +
7.181 + _thread = pthread_l4_cap(thread);
7.182 + _started = true;
7.183 +
7.184 + return L4_EOK;
7.185 +}
7.186 +
7.187 +/* Wait for notification events on files. */
7.188 +
7.189 +long FileNotifier::wait(file_t **file)
7.190 +{
7.191 + std::unique_lock<std::mutex> guard(_lock);
7.192 +
7.193 + while (1)
7.194 + {
7.195 + if (!_affected.empty())
7.196 + {
7.197 + *file = _affected.front();
7.198 + _affected.pop_front();
7.199 + return L4_EOK;
7.200 + }
7.201 + else
7.202 + _notified.wait(guard);
7.203 + }
7.204 +
7.205 + return L4_EOK;
7.206 +}
7.207 +
7.208 +// vim: tabstop=2 expandtab shiftwidth=2
8.1 --- a/libfsserver/include/fsserver/pipe_pager.h Fri Jul 02 23:53:13 2021 +0200
8.2 +++ b/libfsserver/include/fsserver/pipe_pager.h Tue Jul 06 00:45:25 2021 +0200
8.3 @@ -76,7 +76,7 @@
8.4
8.5 /* Notification methods. */
8.6
8.7 - virtual long subscribe(notify_flags_t flags, l4_cap_idx_t *irq);
8.8 + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
8.9
8.10 virtual long unsubscribe();
8.11 };
9.1 --- a/libfsserver/include/fsserver/pipe_paging.h Fri Jul 02 23:53:13 2021 +0200
9.2 +++ b/libfsserver/include/fsserver/pipe_paging.h Tue Jul 06 00:45:25 2021 +0200
9.3 @@ -54,10 +54,10 @@
9.4
9.5 unsigned int _endpoints = 2;
9.6
9.7 - /* Notification IRQs. */
9.8 + /* Notification endpoints. */
9.9
9.10 - l4_cap_idx_t _irqs[2];
9.11 - notify_flags_t _flags[2];
9.12 + l4_cap_idx_t _notifiers[2];
9.13 + notify_flags_t _flags[2], _deferred[2];
9.14
9.15 /* Common functionality. */
9.16
9.17 @@ -75,7 +75,7 @@
9.18
9.19 virtual void notify(bool writing, notify_flags_t flags);
9.20
9.21 - virtual l4_cap_idx_t subscribe(bool writing, notify_flags_t flags);
9.22 + virtual void subscribe(bool writing, l4_cap_idx_t notifier, notify_flags_t flags);
9.23
9.24 virtual void unsubscribe(bool writing);
9.25
10.1 --- a/libfsserver/lib/Makefile Fri Jul 02 23:53:13 2021 +0200
10.2 +++ b/libfsserver/lib/Makefile Tue Jul 06 00:45:25 2021 +0200
10.3 @@ -28,10 +28,14 @@
10.4
10.5 # Individual interfaces.
10.6
10.7 +CLIENT_INTERFACES_CC = notifier
10.8 +
10.9 SERVER_INTERFACES_CC = opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC))
10.10
10.11 # Generated and plain source files.
10.12
10.13 +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
10.14 +
10.15 SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC))
10.16
10.17 PLAIN_SRC_CC = \
10.18 @@ -66,6 +70,7 @@
10.19 # Normal definitions.
10.20
10.21 SRC_CC = \
10.22 + $(CLIENT_INTERFACES_SRC_CC) \
10.23 $(SERVER_INTERFACES_SRC_CC) \
10.24 $(PLAIN_SRC_CC)
10.25
10.26 @@ -81,4 +86,6 @@
10.27 include $(L4DIR)/mk/lib.mk
10.28 include $(IDL_MK_DIR)/interface_rules.mk
10.29
10.30 +$(PLAIN_SRC_CC): $(CLIENT_INTERFACES_SRC_CC)
10.31 +
10.32 $(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC)
11.1 --- a/libfsserver/lib/pipes/pipe_pager.cc Fri Jul 02 23:53:13 2021 +0200
11.2 +++ b/libfsserver/lib/pipes/pipe_pager.cc Tue Jul 06 00:45:25 2021 +0200
11.3 @@ -164,12 +164,12 @@
11.4
11.5 /* Subscribe to notifications. */
11.6
11.7 -long PipePager::subscribe(notify_flags_t flags, l4_cap_idx_t *irq)
11.8 +long PipePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
11.9 {
11.10 /* Readers can subscribe to new data (at end), and pipe closed events.
11.11 Writers can subscribe to new space and pipe closed events. */
11.12
11.13 - *irq = _paging->subscribe(_writing, flags);
11.14 + _paging->subscribe(_writing, notifier, flags);
11.15 return L4_EOK;
11.16 }
11.17
12.1 --- a/libfsserver/lib/pipes/pipe_paging.cc Fri Jul 02 23:53:13 2021 +0200
12.2 +++ b/libfsserver/lib/pipes/pipe_paging.cc Tue Jul 06 00:45:25 2021 +0200
12.3 @@ -19,15 +19,14 @@
12.4 * Boston, MA 02110-1301, USA
12.5 */
12.6
12.7 -#include <l4/sys/irq.h>
12.8 -
12.9 #include <ipc/cap_alloc.h>
12.10 -#include <ipc/irq.h>
12.11 #include <mem/memory_preallocated.h>
12.12
12.13 #include "page_queue_partitioned.h"
12.14 #include "pipe_paging.h"
12.15
12.16 +#include "notifier_client.h"
12.17 +
12.18
12.19
12.20 PipePaging::PipePaging(Memory *memory, offset_t size)
12.21 @@ -44,40 +43,50 @@
12.22 for (unsigned int i = 0; i < 2; i++)
12.23 _regions[i] = NULL;
12.24
12.25 - /* Initialise IRQ objects and flags for notifications. */
12.26 + /* Initialise endpoints and flags for notifications. */
12.27
12.28 for (unsigned int i = 0; i < 2; i++)
12.29 {
12.30 - _irqs[i] = L4_INVALID_CAP;
12.31 + _notifiers[i] = L4_INVALID_CAP;
12.32 _flags[i] = 0;
12.33 + _deferred[i] = 0;
12.34 }
12.35 }
12.36
12.37 -/* Create an IRQ to subscribe to an endpoint's notifications. */
12.38 +/* Subscribe to an endpoint's notifications using a notification endpoint. */
12.39
12.40 -l4_cap_idx_t PipePaging::subscribe(bool writing, notify_flags_t flags)
12.41 +void PipePaging::subscribe(bool writing, l4_cap_idx_t notifier, notify_flags_t flags)
12.42 {
12.43 int i = writing ? 1 : 0;
12.44
12.45 - if (l4_is_invalid_cap(_irqs[i]))
12.46 - ipc_create_irq(&_irqs[i]);
12.47 + if (l4_is_valid_cap(_notifiers[i]))
12.48 + unsubscribe(writing);
12.49
12.50 + _notifiers[i] = notifier;
12.51 _flags[i] = flags;
12.52
12.53 - return _irqs[i];
12.54 + /* Send deferred conditions on behalf of the other endpoint held before
12.55 + subscription occurred. */
12.56 +
12.57 + if (_deferred[i])
12.58 + {
12.59 + notify(!writing, _deferred[i]);
12.60 + _deferred[i] = 0;
12.61 + }
12.62 }
12.63
12.64 -/* Release any IRQ used for an endpoint's notifications. */
12.65 +/* Unsubscribe from an endpoint's notifications. */
12.66
12.67 void PipePaging::unsubscribe(bool writing)
12.68 {
12.69 int i = writing ? 1 : 0;
12.70
12.71 - if (l4_is_valid_cap(_irqs[i]))
12.72 + if (l4_is_valid_cap(_notifiers[i]))
12.73 {
12.74 - ipc_cap_free_um(_irqs[i]);
12.75 - _irqs[i] = L4_INVALID_CAP;
12.76 + ipc_cap_free_um(_notifiers[i]);
12.77 + _notifiers[i] = L4_INVALID_CAP;
12.78 _flags[i] = 0;
12.79 + _deferred[i] = 0;
12.80 }
12.81 }
12.82
12.83 @@ -89,8 +98,20 @@
12.84
12.85 int i = writing ? 0 : 1;
12.86
12.87 - if (l4_is_valid_cap(_irqs[i]) && (flags & _flags[i]))
12.88 - l4_irq_trigger(_irqs[i]);
12.89 + /* Notify the other endpoint or hold any notification for potential future
12.90 + subscription. */
12.91 +
12.92 + if (l4_is_valid_cap(_notifiers[i]))
12.93 + {
12.94 + if (flags & _flags[i])
12.95 + {
12.96 + client_Notifier notifier(_notifiers[i]);
12.97 +
12.98 + notifier.notify(flags & _flags[i]);
12.99 + }
12.100 + }
12.101 + else
12.102 + _deferred[i] = flags;
12.103 }
12.104
12.105 /* Return whether one or more endpoints have detached. */
12.106 @@ -131,14 +152,14 @@
12.107 for (unsigned int i = 0; i < 2; i++)
12.108 discard_region(i);
12.109
12.110 - /* Release IRQs. */
12.111 + /* Release notifiers. */
12.112
12.113 for (unsigned int i = 0; i < 2; i++)
12.114 {
12.115 - if (l4_is_valid_cap(_irqs[i]))
12.116 + if (l4_is_valid_cap(_notifiers[i]))
12.117 {
12.118 - ipc_cap_free_um(_irqs[i]);
12.119 - _irqs[i] = L4_INVALID_CAP;
12.120 + ipc_cap_free_um(_notifiers[i]);
12.121 + _notifiers[i] = L4_INVALID_CAP;
12.122 }
12.123 }
12.124
13.1 --- a/tests/dstest_pipe_client.cc Fri Jul 02 23:53:13 2021 +0200
13.2 +++ b/tests/dstest_pipe_client.cc Tue Jul 06 00:45:25 2021 +0200
13.3 @@ -41,10 +41,19 @@
13.4
13.5 /* Use the writer to fill the pipe with data. */
13.6
13.7 -static void write_pipe(file_t *writer)
13.8 +static void write_pipe(file_t *writer, int number)
13.9 {
13.10 offset_t size = 600;
13.11 char buffer[size];
13.12 + long err;
13.13 +
13.14 + /* Make writers blocking to permit synchronisation. */
13.15 +
13.16 + if ((err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE)))
13.17 + {
13.18 + printf("Could not set pipe #%d as blocking: %s\n", number, l4sys_errtostr(err));
13.19 + return;
13.20 + }
13.21
13.22 for (int loop = 0; loop < 3; loop++)
13.23 {
13.24 @@ -54,7 +63,7 @@
13.25
13.26 offset_t nwritten = client_write(writer, buffer, size);
13.27
13.28 - printf("Written %ld/%ld in #%d of %d/%d to pipe...\n", nwritten, size, region, loop, 2);
13.29 + printf("Written %ld/%ld in #%d of %d/%d to pipe #%d...\n", nwritten, size, region, loop, 2, number);
13.30 }
13.31
13.32 sleep(1);
13.33 @@ -74,23 +83,28 @@
13.34 offset_t size = 600, totals[] = {0, 0};
13.35 bool active[] = {true, true};
13.36 int num_active = 2;
13.37 - char buffer[size];
13.38 - offset_t nread;
13.39 + long err;
13.40 file_t *reader;
13.41 - long err;
13.42 +
13.43 + /* Register the readers for notification. */
13.44 +
13.45 + // NOTE: Use the flags to detect initial conditions!
13.46
13.47 - if ((err = client_wait_init(reader1)) || (err = client_wait_init(reader2)))
13.48 + if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)) ||
13.49 + (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)))
13.50 {
13.51 - printf("Could not initialise waiting for files: %s\n", l4sys_errtostr(err));
13.52 + printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
13.53 return;
13.54 }
13.55
13.56 while (1)
13.57 {
13.58 + char buffer[size];
13.59 + offset_t nread;
13.60 +
13.61 /* Wait for notification of content. */
13.62
13.63 - printf("Waiting...\n");
13.64 - long err = client_wait_files(&reader);
13.65 + err = client_wait_files(&reader);
13.66
13.67 if (err)
13.68 {
13.69 @@ -122,11 +136,11 @@
13.70 }
13.71 }
13.72
13.73 - do
13.74 + while (nread)
13.75 {
13.76 totals[p] += nread;
13.77
13.78 - printf("Read %ld/%ld, total %ld, from pipe #%d...\n", nread, size, totals[p], p + 1);
13.79 + printf("Read %ld/%ld, total %ld, first %c, last %c, from pipe #%d...\n", nread, size, totals[p], *buffer, *(buffer + nread - 1), p + 1);
13.80 #if 0
13.81 for (offset_t i = 0; i < nread; i += 60)
13.82 {
13.83 @@ -136,7 +150,6 @@
13.84 #endif
13.85 nread = client_read(reader, buffer, size);
13.86 }
13.87 - while (nread);
13.88 }
13.89
13.90 printf("Data shown.\n");
13.91 @@ -160,31 +173,13 @@
13.92 return 1;
13.93 }
13.94
13.95 - /* Register the readers for notification. */
13.96 -
13.97 - if ((err = client_subscribe(&reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)) ||
13.98 - (err = client_subscribe(&reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)))
13.99 - {
13.100 - printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
13.101 - return 1;
13.102 - }
13.103 -
13.104 - /* Make the writers blocking to permit synchronisation. */
13.105 -
13.106 - if ((err = client_set_blocking(&writer1, NOTIFY_SPACE_AVAILABLE)) ||
13.107 - (err = client_set_blocking(&writer2, NOTIFY_SPACE_AVAILABLE)))
13.108 - {
13.109 - printf("Could not set as blocking: %s\n", l4sys_errtostr(err));
13.110 - return 1;
13.111 - }
13.112 -
13.113 /* Schedule reader and writer threads. */
13.114
13.115 std::thread *activities[3];
13.116
13.117 activities[0] = new std::thread(read_pipes, &reader1, &reader2);
13.118 - activities[1] = new std::thread(write_pipe, &writer1);
13.119 - activities[2] = new std::thread(write_pipe, &writer2);
13.120 + activities[1] = new std::thread(write_pipe, &writer1, 1);
13.121 + activities[2] = new std::thread(write_pipe, &writer2, 2);
13.122
13.123 for (int i = 0; i < 3; i++)
13.124 activities[i]->join();