1 /* 2 * Notification support. 3 * 4 * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <ipc/cap_alloc.h> 23 24 #include "notification.h" 25 #include "notifier_client.h" 26 27 28 29 /* Initialise endpoints and flags for notifications. */ 30 31 NotificationSupport::NotificationSupport(unsigned int endpoints) 32 : _max_endpoints(endpoints) 33 { 34 _notifiers = new std::set<l4_cap_idx_t>[endpoints]; 35 _flags = new notify_flags_t[endpoints]; 36 _deferred = new notify_flags_t[endpoints]; 37 38 for (unsigned int endpoint = 0; endpoint < _max_endpoints; endpoint++) 39 { 40 _flags[endpoint] = 0; 41 _deferred[endpoint] = 0; 42 } 43 } 44 45 NotificationSupport::~NotificationSupport() 46 { 47 delete _notifiers; 48 delete _flags; 49 delete _deferred; 50 } 51 52 /* Subscribe to an endpoint's notifications using a notification endpoint. */ 53 54 void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) 55 { 56 _notifiers[endpoint].insert(notifier); 57 _flags[endpoint] = flags; 58 59 /* Send deferred conditions held from before subscription occurred. */ 60 61 if (_deferred[endpoint]) 62 { 63 notify(endpoint, _deferred[endpoint]); 64 _deferred[endpoint] = 0; 65 } 66 } 67 68 /* Unsubscribe from an endpoint's notifications. */ 69 70 void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) 71 { 72 std::set<l4_cap_idx_t>::iterator it = _notifiers[endpoint].find(notifier); 73 74 if (it != _notifiers[endpoint].end()) 75 { 76 _notifiers[endpoint].erase(it); 77 _flags[endpoint] = 0; 78 _deferred[endpoint] = 0; 79 ipc_cap_free_um(notifier); 80 } 81 } 82 83 /* Notify the other endpoint. */ 84 85 void NotificationSupport::notify(unsigned int endpoint, notify_flags_t flags, l4_cap_idx_t source) 86 { 87 /* Notify the endpoint or hold any notification for potential future 88 subscription. */ 89 90 if (!_notifiers[endpoint].empty()) 91 { 92 if (flags & _flags[endpoint]) 93 { 94 std::set<l4_cap_idx_t>::iterator it; 95 96 for (it = _notifiers[endpoint].begin(); it != _notifiers[endpoint].end(); it++) 97 { 98 /* Avoid notifying the source of the notification if it is 99 present in the list. */ 100 101 if (l4_is_valid_cap(source) && (*it == source)) 102 continue; 103 104 client_Notifier notifier(*it); 105 106 notifier.notify(flags & _flags[endpoint]); 107 } 108 } 109 } 110 else 111 _deferred[endpoint] = flags; 112 } 113 114 /* Release notifiers for each endpoint. */ 115 116 void NotificationSupport::release_notifiers() 117 { 118 for (unsigned int endpoint = 0; endpoint < _max_endpoints; endpoint++) 119 { 120 std::set<l4_cap_idx_t>::iterator it; 121 122 for (it = _notifiers[endpoint].begin(); it != _notifiers[endpoint].end(); it++) 123 ipc_cap_free_um(*it); 124 125 _notifiers[endpoint].clear(); 126 } 127 } 128 129 // vim: tabstop=4 expandtab shiftwidth=4