# HG changeset patch # User Paul Boddie # Date 1626038468 -7200 # Node ID b287ba4e828bba305497a01bd3a5f6f94c8a2c37 # Parent 9392b442245f4eb194a59d778afc2b62789aa854 Moved notification functionality to a separate base class. diff -r 9392b442245f -r b287ba4e828b libfsserver/include/fsserver/notification.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/notification.h Sun Jul 11 23:21:08 2021 +0200 @@ -0,0 +1,60 @@ +/* + * Notification support. + * + * Copyright (C) 2021 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 + + + +/* Notification support, allowing pipe or file users to receive events due to + activity on those objects. */ + +class NotificationSupport +{ +protected: + /* Endpoint count. */ + + unsigned int _max_endpoints; + + /* Notification endpoints and flags, set up at initialisation for the + appropriate number of endpoints. */ + + std::set *_notifiers; + notify_flags_t *_flags, *_deferred; + + virtual void release_notifiers(); + +public: + explicit NotificationSupport(unsigned int endpoints); + + virtual ~NotificationSupport(); + + virtual void notify(unsigned int endpoint, notify_flags_t flags, l4_cap_idx_t source=L4_INVALID_CAP); + + virtual void subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags); + + virtual void unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9392b442245f -r b287ba4e828b libfsserver/include/fsserver/pipe_paging.h --- a/libfsserver/include/fsserver/pipe_paging.h Sun Jul 11 23:11:39 2021 +0200 +++ b/libfsserver/include/fsserver/pipe_paging.h Sun Jul 11 23:21:08 2021 +0200 @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -32,7 +33,7 @@ /* Pipe paging support, maintaining the sequence of active regions or sections in a pipe. */ -class PipePaging +class PipePaging : public NotificationSupport { protected: Memory *_memory; @@ -56,11 +57,6 @@ unsigned int _endpoints = 2; - /* Notification endpoints. */ - - std::set _notifiers[2]; - notify_flags_t _flags[2], _deferred[2]; - /* Common functionality. */ virtual void discard_region(unsigned int i); @@ -73,7 +69,7 @@ virtual offset_t region_size() { return _size; } - /* Notification support. */ + /* Notification support customised for pipes. */ virtual void notify(bool writing, notify_flags_t flags); diff -r 9392b442245f -r b287ba4e828b libfsserver/lib/Makefile --- a/libfsserver/lib/Makefile Sun Jul 11 23:11:39 2021 +0200 +++ b/libfsserver/lib/Makefile Sun Jul 11 23:21:08 2021 +0200 @@ -52,6 +52,7 @@ files/test_file_accessor.cc \ files/test_file_opener.cc \ generic/accessor.cc \ + generic/notification.cc \ generic/pager.cc \ generic/resource_server.cc \ generic/simple_pager.cc \ diff -r 9392b442245f -r b287ba4e828b libfsserver/lib/generic/notification.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/generic/notification.cc Sun Jul 11 23:21:08 2021 +0200 @@ -0,0 +1,129 @@ +/* + * Notification support. + * + * Copyright (C) 2021 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 + +#include "notification.h" +#include "notifier_client.h" + + + +/* Initialise endpoints and flags for notifications. */ + +NotificationSupport::NotificationSupport(unsigned int endpoints) +: _max_endpoints(endpoints) +{ + _notifiers = new std::set[endpoints]; + _flags = new notify_flags_t[endpoints]; + _deferred = new notify_flags_t[endpoints]; + + for (unsigned int endpoint = 0; endpoint < _max_endpoints; endpoint++) + { + _flags[endpoint] = 0; + _deferred[endpoint] = 0; + } +} + +NotificationSupport::~NotificationSupport() +{ + delete _notifiers; + delete _flags; + delete _deferred; +} + +/* Subscribe to an endpoint's notifications using a notification endpoint. */ + +void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) +{ + _notifiers[endpoint].insert(notifier); + _flags[endpoint] = flags; + + /* Send deferred conditions held from before subscription occurred. */ + + if (_deferred[endpoint]) + { + notify(endpoint, _deferred[endpoint]); + _deferred[endpoint] = 0; + } +} + +/* Unsubscribe from an endpoint's notifications. */ + +void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) +{ + std::set::iterator it = _notifiers[endpoint].find(notifier); + + if (it != _notifiers[endpoint].end()) + { + _notifiers[endpoint].erase(it); + _flags[endpoint] = 0; + _deferred[endpoint] = 0; + ipc_cap_free_um(notifier); + } +} + +/* Notify the other endpoint. */ + +void NotificationSupport::notify(unsigned int endpoint, notify_flags_t flags, l4_cap_idx_t source) +{ + /* Notify the endpoint or hold any notification for potential future + subscription. */ + + if (!_notifiers[endpoint].empty()) + { + if (flags & _flags[endpoint]) + { + std::set::iterator it; + + for (it = _notifiers[endpoint].begin(); it != _notifiers[endpoint].end(); it++) + { + /* Avoid notifying the source of the notification if it is + present in the list. */ + + if (l4_is_valid_cap(source) && (*it == source)) + continue; + + client_Notifier notifier(*it); + + notifier.notify(flags & _flags[endpoint]); + } + } + } + else + _deferred[endpoint] = flags; +} + +/* Release notifiers for each endpoint. */ + +void NotificationSupport::release_notifiers() +{ + for (unsigned int endpoint = 0; endpoint < _max_endpoints; endpoint++) + { + std::set::iterator it; + + for (it = _notifiers[endpoint].begin(); it != _notifiers[endpoint].end(); it++) + ipc_cap_free_um(*it); + + _notifiers[endpoint].clear(); + } +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9392b442245f -r b287ba4e828b libfsserver/lib/pipes/pipe_paging.cc --- a/libfsserver/lib/pipes/pipe_paging.cc Sun Jul 11 23:11:39 2021 +0200 +++ b/libfsserver/lib/pipes/pipe_paging.cc Sun Jul 11 23:21:08 2021 +0200 @@ -19,7 +19,6 @@ * Boston, MA 02110-1301, USA */ -#include #include #include "page_queue_partitioned.h" @@ -30,7 +29,7 @@ PipePaging::PipePaging(Memory *memory, offset_t size) -: _memory(NULL), _size(size) +: NotificationSupport(2), _memory(NULL), _size(size) { /* Reserve space for two pipe regions. */ @@ -42,49 +41,20 @@ for (unsigned int i = 0; i < 2; i++) _regions[i] = NULL; - - /* Initialise endpoints and flags for notifications. */ - - for (unsigned int i = 0; i < 2; i++) - { - _flags[i] = 0; - _deferred[i] = 0; - } } -/* Subscribe to an endpoint's notifications using a notification endpoint. */ +/* Subscribe to an endpoint's notifications using a notifier object. */ void PipePaging::subscribe(bool writing, l4_cap_idx_t notifier, notify_flags_t flags) { - int i = writing ? 1 : 0; - - _notifiers[i].insert(notifier); - _flags[i] = flags; - - /* Send deferred conditions on behalf of the other endpoint held before - subscription occurred. */ - - if (_deferred[i]) - { - notify(!writing, _deferred[i]); - _deferred[i] = 0; - } + NotificationSupport::subscribe(writing ? 1 : 0, notifier, flags); } /* Unsubscribe from an endpoint's notifications. */ void PipePaging::unsubscribe(bool writing, l4_cap_idx_t notifier) { - int i = writing ? 1 : 0; - std::set::iterator it = _notifiers[i].find(notifier); - - if (it != _notifiers[i].end()) - { - _notifiers[i].erase(it); - _flags[i] = 0; - _deferred[i] = 0; - ipc_cap_free_um(notifier); - } + NotificationSupport::unsubscribe(writing ? 1 : 0, notifier); } /* Notify the other endpoint. */ @@ -93,27 +63,7 @@ { /* Let the writer notify the reader, and the other way round. */ - int i = writing ? 0 : 1; - - /* Notify the other endpoint or hold any notification for potential future - subscription. */ - - if (!_notifiers[i].empty()) - { - if (flags & _flags[i]) - { - std::set::iterator it; - - for (it = _notifiers[i].begin(); it != _notifiers[i].end(); it++) - { - client_Notifier notifier(*it); - - notifier.notify(flags & _flags[i]); - } - } - } - else - _deferred[i] = flags; + NotificationSupport::notify(writing ? 0 : 1, flags); } /* Return whether one or more endpoints have detached. */ @@ -156,15 +106,7 @@ /* Release notifiers. */ - for (unsigned int i = 0; i < 2; i++) - { - std::set::iterator it; - - for (it = _notifiers[i].begin(); it != _notifiers[i].end(); it++) - ipc_cap_free_um(*it); - - _notifiers[i].clear(); - } + release_notifiers(); /* Delete the page collection and related objects. */