# HG changeset patch # User Paul Boddie # Date 1647131080 -3600 # Node ID 2a1518ac5891cb6d0c92cea662a7dc56aef0166e # Parent cbf3f5acab81e26d53a6d1a780541de20a9dfebf Support unsubscribing from notifications using a special notifier peer object. diff -r cbf3f5acab81 -r 2a1518ac5891 libfsclient/include/fsclient/notifier.h --- a/libfsclient/include/fsclient/notifier.h Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsclient/include/fsclient/notifier.h Sun Mar 13 01:24:40 2022 +0100 @@ -49,6 +49,10 @@ l4_cap_idx_t endpoint = L4_INVALID_CAP; + /* Server endpoint for unsubscribing. */ + + l4_cap_idx_t peer = L4_INVALID_CAP; + bool is_null() { return l4_is_invalid_cap(endpoint); } }; diff -r cbf3f5acab81 -r 2a1518ac5891 libfsclient/lib/src/Makefile --- a/libfsclient/lib/src/Makefile Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsclient/lib/src/Makefile Sun Mar 13 01:24:40 2022 +0100 @@ -16,7 +16,7 @@ # Individual interfaces. CLIENT_INTERFACES_CC = dataspace directory file filesystem flush \ - mapped_file notification opener \ + mapped_file notification notifier_peer opener \ opener_context pipe pipe_opener # Generated and plain source files. diff -r cbf3f5acab81 -r 2a1518ac5891 libfsclient/lib/src/notifier.cc --- a/libfsclient/lib/src/notifier.cc Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsclient/lib/src/notifier.cc Sun Mar 13 01:24:40 2022 +0100 @@ -30,6 +30,7 @@ #include "notification_client.h" #include "notifier.h" +#include "notifier_peer_client.h" @@ -192,20 +193,33 @@ std::unique_lock state_guard(_state_lock); FileNotificationState &state = file_state(file, true); + long err; /* Create a notification endpoint, if necessary. */ if (state.is_null()) { - long err = ipc_server_new_for_thread(&state.endpoint, file, _thread); + err = ipc_server_new_for_thread(&state.endpoint, file, _thread); if (err) return err; } + /* Subscribe, sending the notification endpoint and obtaining a peer endpoint + for unsubscribing. */ + client_Notification notify(file->ref); - return notify.subscribe(state.endpoint, flags); + err = notify.subscribe(state.endpoint, flags, &state.peer); + + if (err) + { + ipc_cap_free_um(state.endpoint); + _state.erase(file); + return err; + } + + return L4_EOK; } /* Unsubscribe from notification events on a file. */ @@ -221,6 +235,15 @@ if (state.is_null()) return -L4_EINVAL; + /* Unsubscribe via the peer endpoint. */ + + client_NotifierPeer peer(state.peer); + + peer.unsubscribe(); + + ipc_cap_free_um(state.endpoint); + ipc_cap_free_um(state.peer); + _state.erase(file); /* Remove the lock for updating file state. */ diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/include/fsserver/directory_resource.h --- a/libfsserver/include/fsserver/directory_resource.h Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/include/fsserver/directory_resource.h Sun Mar 13 01:24:40 2022 +0100 @@ -63,7 +63,8 @@ /* Notification methods. */ - virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags); + virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags, + l4_cap_idx_t *peer); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/include/fsserver/file_pager.h --- a/libfsserver/include/fsserver/file_pager.h Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/include/fsserver/file_pager.h Sun Mar 13 01:24:40 2022 +0100 @@ -74,7 +74,8 @@ /* Notification methods. */ - virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags); + virtual long subscribe(l4_cap_idx_t endpoint, notify_flags_t flags, + l4_cap_idx_t *peer); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/include/fsserver/notification.h --- a/libfsserver/include/fsserver/notification.h Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/include/fsserver/notification.h Sun Mar 13 01:24:40 2022 +0100 @@ -1,7 +1,7 @@ /* * Notification support. * - * Copyright (C) 2021 Paul Boddie + * Copyright (C) 2021, 2022 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -29,9 +30,14 @@ +/* Forward declaration. */ + +class NotifierPeerEndpoint; + /* Collection data types. */ typedef std::set NotifierSet; +typedef std::map NotifierPeerMap; /* Notification endpoint details. */ @@ -62,6 +68,10 @@ NotificationEndpointList _endpoints; + /* Notifier peer details. */ + + NotifierPeerMap _peers; + /* Deferred notifications for new endpoints. */ notify_flags_t _deferred = 0; @@ -70,7 +80,10 @@ virtual void _notify(unsigned int endpoint, notify_flags_t flags); - virtual void _subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags); + virtual long _subscribe(unsigned int endpoint, l4_cap_idx_t notifier, + notify_flags_t flags, l4_cap_idx_t *peer); + + virtual void _unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier); public: explicit NotificationSupport(unsigned int endpoints=0); @@ -83,9 +96,13 @@ virtual void notify_others(unsigned int endpoint, notify_flags_t flags); - virtual unsigned int subscribe(l4_cap_idx_t notifier, notify_flags_t flags); + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags, + l4_cap_idx_t *peer, unsigned int *endpoint_number); - virtual void subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags); + virtual long subscribe(unsigned int endpoint, l4_cap_idx_t notifier, + notify_flags_t flags, l4_cap_idx_t *peer); + + virtual void unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/include/fsserver/notifier_peer_endpoint.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/notifier_peer_endpoint.h Sun Mar 13 01:24:40 2022 +0100 @@ -0,0 +1,59 @@ +/* + * Notification unsubscribing support. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + + + +/* A notifier endpoint peer for unsubscribing from notifications. */ + +class NotifierPeerEndpoint : public Resource, public NotifierPeer +{ +protected: + NotificationSupport *_notification; + unsigned int _endpoint; + l4_cap_idx_t _notifier; + +public: + explicit NotifierPeerEndpoint(NotificationSupport *notification, + unsigned int endpoint, l4_cap_idx_t notifier); + + virtual ~NotifierPeerEndpoint(); + + /* Server details. */ + + int expected_items(); + + ipc_server_handler_type handler(); + + void *interface() + { return static_cast(this); } + + /* Operations. */ + + virtual long unsubscribe(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/include/fsserver/pipe_pager.h --- a/libfsserver/include/fsserver/pipe_pager.h Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/include/fsserver/pipe_pager.h Sun Mar 13 01:24:40 2022 +0100 @@ -76,7 +76,8 @@ /* Notification methods. */ - virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags); + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags, + l4_cap_idx_t *peer); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/Makefile --- a/libfsserver/lib/Makefile Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/lib/Makefile Sun Mar 13 01:24:40 2022 +0100 @@ -36,7 +36,7 @@ CLIENT_INTERFACES_CC = notifier -SERVER_INTERFACES_CC = opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC)) +SERVER_INTERFACES_CC = notifier_peer opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC)) # Generated and plain source files. @@ -71,6 +71,7 @@ generic/provider_registry.cc \ generic/resource_registry.cc \ generic/notification.cc \ + generic/notifier_peer_endpoint.cc \ generic/pager.cc \ generic/provider.cc \ generic/resource_server.cc \ diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/directories/directory_resource.cc --- a/libfsserver/lib/directories/directory_resource.cc Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/lib/directories/directory_resource.cc Sun Mar 13 01:24:40 2022 +0100 @@ -128,10 +128,10 @@ /* Subscribe to notifications. */ -long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags) +long DirectoryResource::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags, + l4_cap_idx_t *peer) { - _endpoint = _provider->subscribe(endpoint, flags); - return L4_EOK; + return _provider->subscribe(endpoint, flags, peer, &_endpoint); } // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/files/file_pager.cc --- a/libfsserver/lib/files/file_pager.cc Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/lib/files/file_pager.cc Sun Mar 13 01:24:40 2022 +0100 @@ -111,13 +111,13 @@ /* Subscribe to notifications. */ -long FilePager::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags) +long FilePager::subscribe(l4_cap_idx_t endpoint, notify_flags_t flags, + l4_cap_idx_t *peer) { /* Readers can subscribe to new data (flush) and file closed events. Writers can subscribe to file closed events. */ - _endpoint = _provider->subscribe(endpoint, flags); - return L4_EOK; + return _provider->subscribe(endpoint, flags, peer, &_endpoint); } // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/generic/notification.cc --- a/libfsserver/lib/generic/notification.cc Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/lib/generic/notification.cc Sun Mar 13 01:24:40 2022 +0100 @@ -23,6 +23,9 @@ #include "notification.h" #include "notifier_client.h" +#include "notifier_peer_endpoint.h" + +#include "resource_server.h" @@ -41,12 +44,12 @@ /* Subscribe to notifications using a notification object, returning the endpoint number. */ -unsigned int NotificationSupport::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) +long NotificationSupport::subscribe(l4_cap_idx_t notifier, notify_flags_t flags, + l4_cap_idx_t *peer, unsigned int *endpoint_number) { std::lock_guard guard(_lock); unsigned int endpoint = _endpoints.size(); - _endpoints.resize(endpoint + 1); /* Propagate deferred flags for new endpoints. */ @@ -54,15 +57,15 @@ if (_deferred) _endpoints[endpoint].deferred = _deferred; - _subscribe(endpoint, notifier, flags); - - return endpoint; + *endpoint_number = endpoint; + return _subscribe(endpoint, notifier, flags, peer); } /* Subscribe to a specific endpoint's notifications using a notification object. */ -void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) +long NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, + notify_flags_t flags, l4_cap_idx_t *peer) { std::lock_guard guard(_lock); @@ -76,13 +79,25 @@ _endpoints[endpoint].deferred = _deferred; } - _subscribe(endpoint, notifier, flags); + return _subscribe(endpoint, notifier, flags, peer); +} + +/* Unsubscribe from an endpoint's notifications. */ + +void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) +{ + std::lock_guard guard(_lock); + + _unsubscribe(endpoint, notifier); } /* Common subscription functionality. */ -void NotificationSupport::_subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) +long NotificationSupport::_subscribe(unsigned int endpoint, l4_cap_idx_t notifier, + notify_flags_t flags, l4_cap_idx_t *peer) { + /* Record details of the notifier itself. */ + NotificationEndpoint &ep = _endpoints[endpoint]; ep.notifiers.insert(notifier); @@ -95,6 +110,47 @@ _notify(endpoint, ep.deferred); ep.deferred = 0; } + + /* Create a notifier peer for unsubscribing. */ + + NotifierPeerEndpoint *peer_ep = new NotifierPeerEndpoint(this, endpoint, notifier); + + _peers[notifier] = peer_ep; + + long err = ResourceServer(peer_ep).start_thread(peer); + + if (err) + _unsubscribe(endpoint, notifier); + + return err; +} + +void NotificationSupport::_unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) +{ + if (endpoint >= _endpoints.size()) + return; + + NotificationEndpoint &ep = _endpoints[endpoint]; + NotifierSet::iterator it = ep.notifiers.find(notifier); + + if (it != ep.notifiers.end()) + { + ep.notifiers.erase(it); + ipc_cap_free_um(notifier); + + if (ep.notifiers.empty()) + { + ep.flags = 0; + ep.deferred = 0; + } + } + + /* Remove the notifier peer. */ + + NotifierPeerMap::iterator itp = _peers.find(notifier); + + if (itp != _peers.end()) + _peers.erase(itp); } /* Notify a particular endpoint. */ diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/generic/notifier_peer_endpoint.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/generic/notifier_peer_endpoint.cc Sun Mar 13 01:24:40 2022 +0100 @@ -0,0 +1,60 @@ +/* + * Notification support. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "notifier_peer_endpoint.h" +#include "notifier_peer_server.h" + + + +/* Notifier peer endpoint. */ + +NotifierPeerEndpoint::NotifierPeerEndpoint(NotificationSupport *notification, + unsigned int endpoint, + l4_cap_idx_t notifier) +: _notification(notification), _endpoint(endpoint), _notifier(notifier) +{ +} + +NotifierPeerEndpoint::~NotifierPeerEndpoint() +{ +} + +/* Server methods. */ + +int NotifierPeerEndpoint::expected_items() +{ + return NotifierPeer_expected_items; +} + +ipc_server_handler_type NotifierPeerEndpoint::handler() +{ + return (ipc_server_handler_type) handle_NotifierPeer; +} + +/* Unsubscribe a notifier via this peer. */ + +long NotifierPeerEndpoint::unsubscribe() +{ + _notification->unsubscribe(_endpoint, _notifier); + return L4_EOK; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libfsserver/lib/pipes/pipe_pager.cc --- a/libfsserver/lib/pipes/pipe_pager.cc Fri Mar 11 22:16:00 2022 +0100 +++ b/libfsserver/lib/pipes/pipe_pager.cc Sun Mar 13 01:24:40 2022 +0100 @@ -182,13 +182,14 @@ /* Subscribe to notifications. */ -long PipePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags) +long PipePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags, + l4_cap_idx_t *peer) { /* Readers can subscribe to new data (at end), and pipe closed events. Writers can subscribe to new space and pipe closed events. */ - _paging->subscribe(_writing ? PipePaging::WRITER : PipePaging::READER, notifier, flags); - return L4_EOK; + return _paging->subscribe(_writing ? PipePaging::WRITER : PipePaging::READER, + notifier, flags, peer); } // vim: tabstop=4 expandtab shiftwidth=4 diff -r cbf3f5acab81 -r 2a1518ac5891 libsystypes/idl/notification.idl --- a/libsystypes/idl/notification.idl Fri Mar 11 22:16:00 2022 +0100 +++ b/libsystypes/idl/notification.idl Sun Mar 13 01:24:40 2022 +0100 @@ -2,7 +2,9 @@ interface Notification { - /* Subscribe to events. */ + /* Subscribe to events. Unsubscribing is done via the peer returned by the + operation. */ - [opcode(23)] void subscribe(in cap notifier, in notify_flags_t flags); + [opcode(23)] void subscribe(in cap notifier, in notify_flags_t flags, + out cap peer); }; diff -r cbf3f5acab81 -r 2a1518ac5891 libsystypes/idl/notifier_peer.idl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libsystypes/idl/notifier_peer.idl Sun Mar 13 01:24:40 2022 +0100 @@ -0,0 +1,6 @@ +interface NotifierPeer +{ + /* Unsubscribe from events. */ + + [opcode(24)] void unsubscribe(); +};