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 : _min_endpoints(endpoints) 33 { 34 _endpoints.resize(_min_endpoints); 35 } 36 37 /* Subscribe to an endpoint's notifications using a notification endpoint. */ 38 39 void NotificationSupport::subscribe(unsigned int endpoint, l4_cap_idx_t notifier, notify_flags_t flags) 40 { 41 if (endpoint >= _endpoints.size()) 42 _endpoints.resize(endpoint + 1); 43 44 NotificationEndpoint &ep = _endpoints[endpoint]; 45 46 ep.notifiers.insert(notifier); 47 ep.flags = flags; 48 49 /* Send deferred conditions held from before subscription occurred. */ 50 51 if (ep.deferred) 52 { 53 notify(endpoint, ep.deferred); 54 ep.deferred = 0; 55 } 56 } 57 58 /* Unsubscribe from an endpoint's notifications. */ 59 60 void NotificationSupport::unsubscribe(unsigned int endpoint, l4_cap_idx_t notifier) 61 { 62 if (endpoint >= _endpoints.size()) 63 return; 64 65 NotificationEndpoint &ep = _endpoints[endpoint]; 66 NotifierSet::iterator it = ep.notifiers.find(notifier); 67 68 if (it != ep.notifiers.end()) 69 { 70 ep.notifiers.erase(it); 71 ipc_cap_free_um(notifier); 72 73 if (ep.notifiers.empty()) 74 { 75 ep.flags = 0; 76 ep.deferred = 0; 77 } 78 } 79 } 80 81 /* Notify a particular endpoint. */ 82 83 void NotificationSupport::notify(unsigned int endpoint, notify_flags_t flags) 84 { 85 if (endpoint >= _endpoints.size()) 86 return; 87 88 NotificationEndpoint &ep = _endpoints[endpoint]; 89 90 /* Notify the endpoint or hold any notification for potential future 91 subscription. */ 92 93 if (!ep.notifiers.empty()) 94 { 95 if (flags & ep.flags) 96 { 97 NotifierSet::iterator it; 98 99 for (it = ep.notifiers.begin(); it != ep.notifiers.end(); it++) 100 { 101 client_Notifier notifier(*it); 102 103 notifier.notify(flags & ep.flags); 104 } 105 } 106 } 107 else 108 ep.deferred = flags; 109 } 110 111 /* Notify the other endpoints. */ 112 113 void NotificationSupport::notify_others(unsigned int endpoint, notify_flags_t flags) 114 { 115 for (unsigned int i = 0; i < _endpoints.size(); i++) 116 if (i != endpoint) 117 notify(i, flags); 118 } 119 120 /* Release notifiers for each endpoint. */ 121 122 void NotificationSupport::release_notifiers() 123 { 124 for (unsigned int endpoint = 0; endpoint < _endpoints.size(); endpoint++) 125 { 126 NotificationEndpoint &ep = _endpoints[endpoint]; 127 NotifierSet::iterator it; 128 129 for (it = ep.notifiers.begin(); it != ep.notifiers.end(); it++) 130 ipc_cap_free_um(*it); 131 132 ep.notifiers.clear(); 133 ep.flags = 0; 134 ep.deferred = 0; 135 } 136 } 137 138 // vim: tabstop=4 expandtab shiftwidth=4