1.1 --- a/libfsclient/include/fsclient/notifier.h Fri Mar 11 22:16:00 2022 +0100
1.2 +++ b/libfsclient/include/fsclient/notifier.h Sun Mar 13 01:24:40 2022 +0100
1.3 @@ -49,6 +49,10 @@
1.4
1.5 l4_cap_idx_t endpoint = L4_INVALID_CAP;
1.6
1.7 + /* Server endpoint for unsubscribing. */
1.8 +
1.9 + l4_cap_idx_t peer = L4_INVALID_CAP;
1.10 +
1.11 bool is_null() { return l4_is_invalid_cap(endpoint); }
1.12 };
1.13
2.1 --- a/libfsclient/lib/src/Makefile Fri Mar 11 22:16:00 2022 +0100
2.2 +++ b/libfsclient/lib/src/Makefile Sun Mar 13 01:24:40 2022 +0100
2.3 @@ -16,7 +16,7 @@
2.4 # Individual interfaces.
2.5
2.6 CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \
2.7 - mapped_file notification opener \
2.8 + mapped_file notification notifier_peer opener \
2.9 opener_context pipe pipe_opener
2.10
2.11 # Generated and plain source files.
3.1 --- a/libfsclient/lib/src/notifier.cc Fri Mar 11 22:16:00 2022 +0100
3.2 +++ b/libfsclient/lib/src/notifier.cc Sun Mar 13 01:24:40 2022 +0100
3.3 @@ -30,6 +30,7 @@
3.4
3.5 #include "notification_client.h"
3.6 #include "notifier.h"
3.7 +#include "notifier_peer_client.h"
3.8
3.9
3.10
3.11 @@ -192,20 +193,33 @@
3.12 std::unique_lock<std::mutex> state_guard(_state_lock);
3.13
3.14 FileNotificationState &state = file_state(file, true);
3.15 + long err;
3.16
3.17 /* Create a notification endpoint, if necessary. */
3.18
3.19 if (state.is_null())
3.20 {
3.21 - long err = ipc_server_new_for_thread(&state.endpoint, file, _thread);
3.22 + err = ipc_server_new_for_thread(&state.endpoint, file, _thread);
3.23
3.24 if (err)
3.25 return err;
3.26 }
3.27
3.28 + /* Subscribe, sending the notification endpoint and obtaining a peer endpoint
3.29 + for unsubscribing. */
3.30 +
3.31 client_Notification notify(file->ref);
3.32
3.33 - return notify.subscribe(state.endpoint, flags);
3.34 + err = notify.subscribe(state.endpoint, flags, &state.peer);
3.35 +
3.36 + if (err)
3.37 + {
3.38 + ipc_cap_free_um(state.endpoint);
3.39 + _state.erase(file);
3.40 + return err;
3.41 + }
3.42 +
3.43 + return L4_EOK;
3.44 }
3.45
3.46 /* Unsubscribe from notification events on a file. */
3.47 @@ -221,6 +235,15 @@
3.48 if (state.is_null())
3.49 return -L4_EINVAL;
3.50
3.51 + /* Unsubscribe via the peer endpoint. */
3.52 +
3.53 + client_NotifierPeer peer(state.peer);
3.54 +
3.55 + peer.unsubscribe();
3.56 +
3.57 + ipc_cap_free_um(state.endpoint);
3.58 + ipc_cap_free_um(state.peer);
3.59 +
3.60 _state.erase(file);
3.61
3.62 /* Remove the lock for updating file state. */
4.1 --- a/libfsserver/include/fsserver/directory_resource.h Fri Mar 11 22:16:00 2022 +0100
4.2 +++ b/libfsserver/include/fsserver/directory_resource.h Sun Mar 13 01:24:40 2022 +0100
4.3 @@ -63,7 +63,8 @@
4.4
4.5 /* Notification methods. */
4.6
4.7 - virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags);
4.8 + virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags,
4.9 + l4_cap_idx_t *peer);
4.10 };
4.11
4.12 // vim: tabstop=4 expandtab shiftwidth=4
5.1 --- a/libfsserver/include/fsserver/file_pager.h Fri Mar 11 22:16:00 2022 +0100
5.2 +++ b/libfsserver/include/fsserver/file_pager.h Sun Mar 13 01:24:40 2022 +0100
5.3 @@ -74,7 +74,8 @@
5.4
5.5 /* Notification methods. */
5.6
5.7 - virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags);
5.8 + virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags,
5.9 + l4_cap_idx_t *peer);
5.10 };
5.11
5.12 // vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/libfsserver/include/fsserver/notification.h Fri Mar 11 22:16:00 2022 +0100
6.2 +++ b/libfsserver/include/fsserver/notification.h Sun Mar 13 01:24:40 2022 +0100
6.3 @@ -1,7 +1,7 @@
6.4 /*
6.5 * Notification support.
6.6 *
6.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
6.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
6.9 *
6.10 * This program is free software; you can redistribute it and/or
6.11 * modify it under the terms of the GNU General Public License as
6.12 @@ -21,6 +21,7 @@
6.13
6.14 #pragma once
6.15
6.16 +#include <map>
6.17 #include <mutex>
6.18 #include <set>
6.19 #include <vector>
6.20 @@ -29,9 +30,14 @@
6.21
6.22
6.23
6.24 +/* Forward declaration. */
6.25 +
6.26 +class NotifierPeerEndpoint;
6.27 +
6.28 /* Collection data types. */
6.29
6.30 typedef std::set<l4_cap_idx_t> NotifierSet;
6.31 +typedef std::map<l4_cap_idx_t, NotifierPeerEndpoint *> NotifierPeerMap;
6.32
6.33 /* Notification endpoint details. */
6.34
6.35 @@ -62,6 +68,10 @@
6.36
6.37 NotificationEndpointList _endpoints;
6.38
6.39 + /* Notifier peer details. */
6.40 +
6.41 + NotifierPeerMap _peers;
6.42 +
6.43 /* Deferred notifications for new endpoints. */
6.44
6.45 notify_flags_t _deferred = 0;
6.46 @@ -70,7 +80,10 @@
6.47
6.48 virtual void _notify(unsigned int endpoint, notify_flags_t flags);
6.49
6.50 - virtual void _subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags);
6.51 + virtual long _subscribe(unsigned int endpoint, l4_cap_idx_t notifier,
6.52 + notify_flags_t flags, l4_cap_idx_t *peer);
6.53 +
6.54 + virtual void _unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier);
6.55
6.56 public:
6.57 explicit NotificationSupport(unsigned int endpoints=0);
6.58 @@ -83,9 +96,13 @@
6.59
6.60 virtual void notify_others(unsigned int endpoint, notify_flags_t flags);
6.61
6.62 - virtual unsigned int subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
6.63 + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags,
6.64 + l4_cap_idx_t *peer, unsigned int *endpoint_number);
6.65
6.66 - virtual void subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags);
6.67 + virtual long subscribe(unsigned int endpoint, l4_cap_idx_t notifier,
6.68 + notify_flags_t flags, l4_cap_idx_t *peer);
6.69 +
6.70 + virtual void unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier);
6.71 };
6.72
6.73 // vim: tabstop=4 expandtab shiftwidth=4
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/libfsserver/include/fsserver/notifier_peer_endpoint.h Sun Mar 13 01:24:40 2022 +0100
7.3 @@ -0,0 +1,59 @@
7.4 +/*
7.5 + * Notification unsubscribing support.
7.6 + *
7.7 + * Copyright (C) 2021, 2022 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 +#pragma once
7.26 +
7.27 +#include <fsserver/notification.h>
7.28 +#include <fsserver/notifier_peer_interface.h>
7.29 +#include <fsserver/resource.h>
7.30 +
7.31 +
7.32 +
7.33 +/* A notifier endpoint peer for unsubscribing from notifications. */
7.34 +
7.35 +class NotifierPeerEndpoint : public Resource, public NotifierPeer
7.36 +{
7.37 +protected:
7.38 + NotificationSupport *_notification;
7.39 + unsigned int _endpoint;
7.40 + l4_cap_idx_t _notifier;
7.41 +
7.42 +public:
7.43 + explicit NotifierPeerEndpoint(NotificationSupport *notification,
7.44 + unsigned int endpoint, l4_cap_idx_t notifier);
7.45 +
7.46 + virtual ~NotifierPeerEndpoint();
7.47 +
7.48 + /* Server details. */
7.49 +
7.50 + int expected_items();
7.51 +
7.52 + ipc_server_handler_type handler();
7.53 +
7.54 + void *interface()
7.55 + { return static_cast<NotifierPeer *>(this); }
7.56 +
7.57 + /* Operations. */
7.58 +
7.59 + virtual long unsubscribe();
7.60 +};
7.61 +
7.62 +// vim: tabstop=4 expandtab shiftwidth=4
8.1 --- a/libfsserver/include/fsserver/pipe_pager.h Fri Mar 11 22:16:00 2022 +0100
8.2 +++ b/libfsserver/include/fsserver/pipe_pager.h Sun Mar 13 01:24:40 2022 +0100
8.3 @@ -76,7 +76,8 @@
8.4
8.5 /* Notification methods. */
8.6
8.7 - virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
8.8 + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags,
8.9 + l4_cap_idx_t *peer);
8.10 };
8.11
8.12 // vim: tabstop=4 expandtab shiftwidth=4
9.1 --- a/libfsserver/lib/Makefile Fri Mar 11 22:16:00 2022 +0100
9.2 +++ b/libfsserver/lib/Makefile Sun Mar 13 01:24:40 2022 +0100
9.3 @@ -36,7 +36,7 @@
9.4
9.5 CLIENT_INTERFACES_CC = notifier
9.6
9.7 -SERVER_INTERFACES_CC = opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC))
9.8 +SERVER_INTERFACES_CC = notifier_peer opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC))
9.9
9.10 # Generated and plain source files.
9.11
9.12 @@ -71,6 +71,7 @@
9.13 generic/provider_registry.cc \
9.14 generic/resource_registry.cc \
9.15 generic/notification.cc \
9.16 + generic/notifier_peer_endpoint.cc \
9.17 generic/pager.cc \
9.18 generic/provider.cc \
9.19 generic/resource_server.cc \
10.1 --- a/libfsserver/lib/directories/directory_resource.cc Fri Mar 11 22:16:00 2022 +0100
10.2 +++ b/libfsserver/lib/directories/directory_resource.cc Sun Mar 13 01:24:40 2022 +0100
10.3 @@ -128,10 +128,10 @@
10.4
10.5 /* Subscribe to notifications. */
10.6
10.7 -long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags)
10.8 +long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags,
10.9 + l4_cap_idx_t *peer)
10.10 {
10.11 - _endpoint = _provider->subscribe(endpoint, flags);
10.12 - return L4_EOK;
10.13 + return _provider->subscribe(endpoint, flags, peer, &_endpoint);
10.14 }
10.15
10.16 // vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/libfsserver/lib/files/file_pager.cc Fri Mar 11 22:16:00 2022 +0100
11.2 +++ b/libfsserver/lib/files/file_pager.cc Sun Mar 13 01:24:40 2022 +0100
11.3 @@ -111,13 +111,13 @@
11.4
11.5 /* Subscribe to notifications. */
11.6
11.7 -long FilePager::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags)
11.8 +long FilePager::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags,
11.9 + l4_cap_idx_t *peer)
11.10 {
11.11 /* Readers can subscribe to new data (flush) and file closed events.
11.12 Writers can subscribe to file closed events. */
11.13
11.14 - _endpoint = _provider->subscribe(endpoint, flags);
11.15 - return L4_EOK;
11.16 + return _provider->subscribe(endpoint, flags, peer, &_endpoint);
11.17 }
11.18
11.19 // vim: tabstop=4 expandtab shiftwidth=4
12.1 --- a/libfsserver/lib/generic/notification.cc Fri Mar 11 22:16:00 2022 +0100
12.2 +++ b/libfsserver/lib/generic/notification.cc Sun Mar 13 01:24:40 2022 +0100
12.3 @@ -23,6 +23,9 @@
12.4
12.5 #include "notification.h"
12.6 #include "notifier_client.h"
12.7 +#include "notifier_peer_endpoint.h"
12.8 +
12.9 +#include "resource_server.h"
12.10
12.11
12.12
12.13 @@ -41,12 +44,12 @@
12.14 /* Subscribe to notifications using a notification object, returning the
12.15 endpoint number. */
12.16
12.17 -unsigned int NotificationSupport::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
12.18 +long NotificationSupport::subscribe(l4_cap_idx_t notifier, notify_flags_t flags,
12.19 + l4_cap_idx_t *peer, unsigned int *endpoint_number)
12.20 {
12.21 std::lock_guard<std::mutex> guard(_lock);
12.22
12.23 unsigned int endpoint = _endpoints.size();
12.24 -
12.25 _endpoints.resize(endpoint + 1);
12.26
12.27 /* Propagate deferred flags for new endpoints. */
12.28 @@ -54,15 +57,15 @@
12.29 if (_deferred)
12.30 _endpoints[endpoint].deferred = _deferred;
12.31
12.32 - _subscribe(endpoint, notifier, flags);
12.33 -
12.34 - return endpoint;
12.35 + *endpoint_number = endpoint;
12.36 + return _subscribe(endpoint, notifier, flags, peer);
12.37 }
12.38
12.39 /* Subscribe to a specific endpoint's notifications using a notification
12.40 object. */
12.41
12.42 -void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags)
12.43 +long NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier,
12.44 + notify_flags_t flags, l4_cap_idx_t *peer)
12.45 {
12.46 std::lock_guard<std::mutex> guard(_lock);
12.47
12.48 @@ -76,13 +79,25 @@
12.49 _endpoints[endpoint].deferred = _deferred;
12.50 }
12.51
12.52 - _subscribe(endpoint, notifier, flags);
12.53 + return _subscribe(endpoint, notifier, flags, peer);
12.54 +}
12.55 +
12.56 +/* Unsubscribe from an endpoint's notifications. */
12.57 +
12.58 +void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier)
12.59 +{
12.60 + std::lock_guard<std::mutex> guard(_lock);
12.61 +
12.62 + _unsubscribe(endpoint, notifier);
12.63 }
12.64
12.65 /* Common subscription functionality. */
12.66
12.67 -void NotificationSupport::_subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags)
12.68 +long NotificationSupport::_subscribe(unsigned int endpoint, l4_cap_idx_t notifier,
12.69 + notify_flags_t flags, l4_cap_idx_t *peer)
12.70 {
12.71 + /* Record details of the notifier itself. */
12.72 +
12.73 NotificationEndpoint &ep = _endpoints[endpoint];
12.74
12.75 ep.notifiers.insert(notifier);
12.76 @@ -95,6 +110,47 @@
12.77 _notify(endpoint, ep.deferred);
12.78 ep.deferred = 0;
12.79 }
12.80 +
12.81 + /* Create a notifier peer for unsubscribing. */
12.82 +
12.83 + NotifierPeerEndpoint *peer_ep = new NotifierPeerEndpoint(this, endpoint, notifier);
12.84 +
12.85 + _peers[notifier] = peer_ep;
12.86 +
12.87 + long err = ResourceServer(peer_ep).start_thread(peer);
12.88 +
12.89 + if (err)
12.90 + _unsubscribe(endpoint, notifier);
12.91 +
12.92 + return err;
12.93 +}
12.94 +
12.95 +void NotificationSupport::_unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier)
12.96 +{
12.97 + if (endpoint >= _endpoints.size())
12.98 + return;
12.99 +
12.100 + NotificationEndpoint &ep = _endpoints[endpoint];
12.101 + NotifierSet::iterator it = ep.notifiers.find(notifier);
12.102 +
12.103 + if (it != ep.notifiers.end())
12.104 + {
12.105 + ep.notifiers.erase(it);
12.106 + ipc_cap_free_um(notifier);
12.107 +
12.108 + if (ep.notifiers.empty())
12.109 + {
12.110 + ep.flags = 0;
12.111 + ep.deferred = 0;
12.112 + }
12.113 + }
12.114 +
12.115 + /* Remove the notifier peer. */
12.116 +
12.117 + NotifierPeerMap::iterator itp = _peers.find(notifier);
12.118 +
12.119 + if (itp != _peers.end())
12.120 + _peers.erase(itp);
12.121 }
12.122
12.123 /* Notify a particular endpoint. */
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/libfsserver/lib/generic/notifier_peer_endpoint.cc Sun Mar 13 01:24:40 2022 +0100
13.3 @@ -0,0 +1,60 @@
13.4 +/*
13.5 + * Notification support.
13.6 + *
13.7 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
13.8 + *
13.9 + * This program is free software; you can redistribute it and/or
13.10 + * modify it under the terms of the GNU General Public License as
13.11 + * published by the Free Software Foundation; either version 2 of
13.12 + * the License, or (at your option) any later version.
13.13 + *
13.14 + * This program is distributed in the hope that it will be useful,
13.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
13.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13.17 + * GNU General Public License for more details.
13.18 + *
13.19 + * You should have received a copy of the GNU General Public License
13.20 + * along with this program; if not, write to the Free Software
13.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
13.22 + * Boston, MA 02110-1301, USA
13.23 + */
13.24 +
13.25 +#include "notifier_peer_endpoint.h"
13.26 +#include "notifier_peer_server.h"
13.27 +
13.28 +
13.29 +
13.30 +/* Notifier peer endpoint. */
13.31 +
13.32 +NotifierPeerEndpoint::NotifierPeerEndpoint(NotificationSupport *notification,
13.33 + unsigned int endpoint,
13.34 + l4_cap_idx_t notifier)
13.35 +: _notification(notification), _endpoint(endpoint), _notifier(notifier)
13.36 +{
13.37 +}
13.38 +
13.39 +NotifierPeerEndpoint::~NotifierPeerEndpoint()
13.40 +{
13.41 +}
13.42 +
13.43 +/* Server methods. */
13.44 +
13.45 +int NotifierPeerEndpoint::expected_items()
13.46 +{
13.47 + return NotifierPeer_expected_items;
13.48 +}
13.49 +
13.50 +ipc_server_handler_type NotifierPeerEndpoint::handler()
13.51 +{
13.52 + return (ipc_server_handler_type) handle_NotifierPeer;
13.53 +}
13.54 +
13.55 +/* Unsubscribe a notifier via this peer. */
13.56 +
13.57 +long NotifierPeerEndpoint::unsubscribe()
13.58 +{
13.59 + _notification->unsubscribe(_endpoint, _notifier);
13.60 + return L4_EOK;
13.61 +}
13.62 +
13.63 +// vim: tabstop=4 expandtab shiftwidth=4
14.1 --- a/libfsserver/lib/pipes/pipe_pager.cc Fri Mar 11 22:16:00 2022 +0100
14.2 +++ b/libfsserver/lib/pipes/pipe_pager.cc Sun Mar 13 01:24:40 2022 +0100
14.3 @@ -182,13 +182,14 @@
14.4
14.5 /* Subscribe to notifications. */
14.6
14.7 -long PipePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
14.8 +long PipePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags,
14.9 + l4_cap_idx_t *peer)
14.10 {
14.11 /* Readers can subscribe to new data (at end), and pipe closed events.
14.12 Writers can subscribe to new space and pipe closed events. */
14.13
14.14 - _paging->subscribe(_writing ? PipePaging::WRITER : PipePaging::READER, notifier, flags);
14.15 - return L4_EOK;
14.16 + return _paging->subscribe(_writing ? PipePaging::WRITER : PipePaging::READER,
14.17 + notifier, flags, peer);
14.18 }
14.19
14.20 // vim: tabstop=4 expandtab shiftwidth=4
15.1 --- a/libsystypes/idl/notification.idl Fri Mar 11 22:16:00 2022 +0100
15.2 +++ b/libsystypes/idl/notification.idl Sun Mar 13 01:24:40 2022 +0100
15.3 @@ -2,7 +2,9 @@
15.4
15.5 interface Notification
15.6 {
15.7 - /* Subscribe to events. */
15.8 + /* Subscribe to events. Unsubscribing is done via the peer returned by the
15.9 + operation. */
15.10
15.11 - [opcode(23)] void subscribe(in cap notifier, in notify_flags_t flags);
15.12 + [opcode(23)] void subscribe(in cap notifier, in notify_flags_t flags,
15.13 + out cap peer);
15.14 };
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/libsystypes/idl/notifier_peer.idl Sun Mar 13 01:24:40 2022 +0100
16.3 @@ -0,0 +1,6 @@
16.4 +interface NotifierPeer
16.5 +{
16.6 + /* Unsubscribe from events. */
16.7 +
16.8 + [opcode(24)] void unsubscribe();
16.9 +};