1 /* 2 * Resource server functionality. 3 * 4 * Copyright (C) 2018, 2019, 2020, 2021, 2022 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 <l4/re/env.h> 23 #include <l4/sys/types.h> 24 25 #include <pthread-l4.h> 26 #include <pthread.h> 27 28 #include "resource_server.h" 29 30 31 32 /* Convenience server methods. */ 33 34 /* Bind to a named IPC gate capability. */ 35 36 long ResourceServer::bind(const char *name) 37 { 38 return ipc_server_bind(name, (l4_umword_t) _config, &_config->server); 39 } 40 41 /* Start in the same thread indicating whether the server can be finalised. If 42 so, deletion notifications will be used. */ 43 44 long ResourceServer::start(bool finalisation) 45 { 46 resource_init_config(_config, _resource); 47 _config->thread = pthread_l4_cap(pthread_self()); 48 49 /* NOTE: On MIPS32, at least, in a payload started by libexec, the main thread 50 is not necessarily returned correctly. */ 51 52 if (l4_is_invalid_cap(_config->thread)) 53 _config->thread = l4re_env()->main_thread; 54 55 if (finalisation) 56 { 57 _config->finaliser = resource_same_thread_finaliser; 58 _config->notifications = 1; 59 _config->auto_deletion = 1; 60 } 61 62 return resource_start_config(_config, _resource); 63 } 64 65 /* Start serving a resource in an existing thread. The resource will not be 66 finalised. */ 67 68 long ResourceServer::start_in_thread(l4_cap_idx_t thread) 69 { 70 resource_init_config(_config, _resource); 71 resource_set_config_threaded(_config, thread, 1, 0, 0); 72 73 return resource_start_config(_config, _resource); 74 } 75 76 /* Start serving a resource in a new thread. */ 77 78 long ResourceServer::start_thread(bool finalisation, bool auto_deletion) 79 { 80 pthread_t thread; 81 pthread_attr_t attr; 82 long err; 83 84 pthread_attr_init(&attr); 85 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 86 87 resource_init_config(_config, _resource); 88 89 err = pthread_create(&thread, &attr, ipc_server_start_mainloop, _config); 90 if (err) 91 return err; 92 93 resource_set_config_threaded(_config, pthread_l4_cap(thread), 1, finalisation, 94 auto_deletion); 95 96 return resource_start_config(_config, _resource); 97 } 98 99 /* A convenience method starting a thread and returning the server capability 100 employed via the given parameter. */ 101 102 long ResourceServer::start_thread(l4_cap_idx_t *server, bool finalisation, 103 bool auto_deletion) 104 { 105 long err = start_thread(finalisation, auto_deletion); 106 107 if (!err) 108 *server = _config->server; 109 110 return err; 111 } 112 113 114 115 /* Initialise a server configuration for a resource. */ 116 117 void resource_init_config(ipc_server_config_type *config, Resource *resource) 118 { 119 ipc_server_default_config_type default_config = resource->config(); 120 121 config->handler_obj = resource->interface(); 122 config->finaliser_obj = resource; 123 config->expected_items = default_config.expected_items; 124 config->handler = default_config.handler; 125 } 126 127 /* Set a configuration to be threaded. */ 128 129 void resource_set_config_threaded(ipc_server_config_type *config, 130 l4_cap_idx_t thread, int separate_thread, 131 int finalisation, int auto_deletion) 132 { 133 if (finalisation) 134 config->finaliser = resource_thread_finaliser; 135 136 config->config_thread = separate_thread; 137 config->thread = thread; 138 config->notifications = finalisation; 139 config->auto_deletion = auto_deletion; 140 } 141 142 /* Activate a resource and start a server for it. */ 143 144 long resource_start_config(ipc_server_config_type *config, Resource *resource) 145 { 146 resource->activate(); 147 long err = ipc_server_start_config(config); 148 149 /* Discard any server resources if starting it failed. */ 150 151 if (err) 152 { 153 ipc_server_finalise_config(config); 154 ipc_server_discard_thread(config); 155 } 156 157 return err; 158 } 159 160 161 162 /* A finaliser for exposed resources in the same thread. */ 163 164 void resource_same_thread_finaliser(ipc_server_config_type *config) 165 { 166 Resource *resource = reinterpret_cast<Resource *>(config->finaliser_obj); 167 168 /* Close but do not delete the resource since it is assumed that it is being 169 managed by the thread. */ 170 171 resource->close(); 172 173 /* Release the capabilities. */ 174 175 ipc_server_finalise_config(config); 176 delete config; 177 } 178 179 /* A finaliser for exposed resources in a different thread. */ 180 181 void resource_thread_finaliser(ipc_server_config_type *config) 182 { 183 Resource *resource = reinterpret_cast<Resource *>(config->finaliser_obj); 184 185 /* Close and delete the resource. */ 186 187 resource->close(); 188 delete resource; 189 190 /* Release the capabilities. */ 191 192 ipc_server_finalise_config(config); 193 delete config; 194 } 195 196 // vim: tabstop=2 expandtab shiftwidth=2