source: mainline/uspace/lib/c/generic/async/ports.c@ f0cc1c64

Last change on this file since f0cc1c64 was cb20b05, checked in by Jiri Svoboda <jiri@…>, 9 days ago

Fix missing argument when destroying async port.

  • Property mode set to 100644
File size: 9.0 KB
RevLine 
[49a796f1]1/*
[3951046]2 * Copyright (c) 2025 Jiri Svoboda
[49a796f1]3 * Copyright (c) 2006 Ondrej Palkovsky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[4805495]30#define _LIBC_ASYNC_C_
[49a796f1]31#include <ipc/ipc.h>
32#include <async.h>
33#include "../private/async.h"
[4805495]34#undef _LIBC_ASYNC_C_
[49a796f1]35
36#include <ipc/irq.h>
37#include <ipc/event.h>
38#include <fibril.h>
39#include <adt/hash_table.h>
40#include <adt/hash.h>
41#include <adt/list.h>
42#include <assert.h>
43#include <errno.h>
[bd41ac52]44#include <time.h>
[05882233]45#include <barrier.h>
[49a796f1]46#include <stdbool.h>
47#include <stdlib.h>
48#include <mem.h>
49#include <stdlib.h>
50#include <macros.h>
51#include <as.h>
52#include <abi/mm/as.h>
[f787c8e]53#include "../private/fibril.h"
[49a796f1]54
55/** Interface data */
56typedef struct {
57 ht_link_t link;
58
59 /** Interface ID */
60 iface_t iface;
61
[3951046]62 /** Interface connection handler */
63 async_port_handler_t handler;
[49a796f1]64
[3951046]65 /** Client data */
66 void *data;
[49a796f1]67} interface_t;
68
69/* Port data */
70typedef struct {
71 ht_link_t link;
72
73 /** Port ID */
74 port_id_t id;
75
[3951046]76 /** Port interfaces */
77 hash_table_t interface_hash_table;
[49a796f1]78} port_t;
79
80/** Default fallback fibril function.
81 *
82 * This fallback fibril function gets called on incomming connections that do
83 * not have a specific handler defined.
84 *
[984a9ba]85 * @param call Data of the incoming call.
86 * @param arg Local argument
[49a796f1]87 *
88 */
[984a9ba]89static void default_fallback_port_handler(ipc_call_t *call, void *arg)
[49a796f1]90{
[984a9ba]91 async_answer_0(call, ENOENT);
[49a796f1]92}
93
94static async_port_handler_t fallback_port_handler =
95 default_fallback_port_handler;
96static void *fallback_port_data = NULL;
97
[3951046]98/** Futex guarding the port hash table. */
99static fibril_rmutex_t port_mutex;
100static hash_table_t port_hash_table;
101/** Next available port ID */
102static port_id_t port_id_avail = 0;
[49a796f1]103
[5e801dc]104static size_t interface_key_hash(const void *key)
[49a796f1]105{
[5e801dc]106 const iface_t *iface = key;
107 return *iface;
[49a796f1]108}
109
110static size_t interface_hash(const ht_link_t *item)
111{
112 interface_t *interface = hash_table_get_inst(item, interface_t, link);
113 return interface_key_hash(&interface->iface);
114}
115
[0db0df2]116static bool interface_key_equal(const void *key, size_t hash, const ht_link_t *item)
[49a796f1]117{
[5e801dc]118 const iface_t *iface = key;
[49a796f1]119 interface_t *interface = hash_table_get_inst(item, interface_t, link);
[5e801dc]120 return *iface == interface->iface;
[49a796f1]121}
122
123/** Operations for the port hash table. */
[61eb2ce2]124static const hash_table_ops_t interface_hash_table_ops = {
[49a796f1]125 .hash = interface_hash,
126 .key_hash = interface_key_hash,
127 .key_equal = interface_key_equal,
128 .equal = NULL,
129 .remove_callback = NULL
130};
131
[5e801dc]132static size_t port_key_hash(const void *key)
[49a796f1]133{
[5e801dc]134 const port_id_t *port_id = key;
135 return *port_id;
[49a796f1]136}
137
138static size_t port_hash(const ht_link_t *item)
139{
140 port_t *port = hash_table_get_inst(item, port_t, link);
141 return port_key_hash(&port->id);
142}
143
[0db0df2]144static bool port_key_equal(const void *key, size_t hash, const ht_link_t *item)
[49a796f1]145{
[5e801dc]146 const port_id_t *port_id = key;
[49a796f1]147 port_t *port = hash_table_get_inst(item, port_t, link);
[5e801dc]148 return *port_id == port->id;
[49a796f1]149}
150
151/** Operations for the port hash table. */
[61eb2ce2]152static const hash_table_ops_t port_hash_table_ops = {
[49a796f1]153 .hash = port_hash,
154 .key_hash = port_key_hash,
155 .key_equal = port_key_equal,
156 .equal = NULL,
157 .remove_callback = NULL
158};
159
[3951046]160static interface_t *async_new_interface(port_t *port, iface_t iface,
161 async_port_handler_t handler, void *data)
[49a796f1]162{
163 interface_t *interface =
164 (interface_t *) malloc(sizeof(interface_t));
165 if (!interface)
166 return NULL;
167 interface->iface = iface;
[3951046]168 interface->handler = handler;
169 interface->data = data;
[49a796f1]170
[3951046]171 hash_table_insert(&port->interface_hash_table, &interface->link);
[49a796f1]172
173 return interface;
174}
175
[3951046]176static port_t *async_new_port(void)
[49a796f1]177{
[5c76cc61]178 // TODO: Move the malloc out of critical section.
[49a796f1]179 port_t *port = (port_t *) malloc(sizeof(port_t));
180 if (!port)
181 return NULL;
182
[3951046]183 bool ret = hash_table_create(&port->interface_hash_table, 0, 0,
184 &interface_hash_table_ops);
185 if (!ret) {
186 free(port);
187 return NULL;
188 }
[49a796f1]189
[3951046]190 port_id_t id = port_id_avail;
191 port_id_avail++;
[49a796f1]192
[3951046]193 port->id = id;
194 hash_table_insert(&port_hash_table, &port->link);
[49a796f1]195
196 return port;
197}
198
[ca48672]199static bool destroy_if(ht_link_t *link, void *arg)
200{
201 port_t *port = (port_t *)arg;
202
203 hash_table_remove_item(&port->interface_hash_table, link);
204 return false;
205}
206
207static void async_delete_port(port_t *port)
208{
209 /* Destroy interfaces */
[cb20b05]210 hash_table_apply(&port->interface_hash_table, destroy_if, port);
[ca48672]211
212 hash_table_destroy(&port->interface_hash_table);
213 free(port);
214}
215
[49a796f1]216errno_t async_create_port_internal(iface_t iface, async_port_handler_t handler,
217 void *data, port_id_t *port_id)
218{
219 interface_t *interface;
220
[3951046]221 fibril_rmutex_lock(&port_mutex);
[49a796f1]222
[3951046]223 port_t *port = async_new_port();
224 if (port == NULL) {
225 fibril_rmutex_unlock(&port_mutex);
[49a796f1]226 return ENOMEM;
227 }
228
[3951046]229 interface = async_new_interface(port, iface, handler, data);
230 if (interface == NULL) {
[ca48672]231 async_delete_port(port);
[3951046]232 fibril_rmutex_unlock(&port_mutex);
[49a796f1]233 return ENOMEM;
234 }
235
236 *port_id = port->id;
[3951046]237 fibril_rmutex_unlock(&port_mutex);
[49a796f1]238 return EOK;
239}
240
[ca48672]241errno_t async_port_create_interface(port_id_t port_id, iface_t iface,
242 async_port_handler_t handler, void *data)
243{
244 ht_link_t *link;
245 port_t *port;
246 interface_t *interface;
247
248 fibril_rmutex_lock(&port_mutex);
249 link = hash_table_find(&port_hash_table, &port_id);
250 assert(link != NULL);
251 port = hash_table_get_inst(link, port_t, link);
252
253 interface = async_new_interface(port, iface, handler, data);
254 if (interface == NULL) {
255 fibril_rmutex_unlock(&port_mutex);
256 return ENOMEM;
257 }
258
259 fibril_rmutex_unlock(&port_mutex);
260 return EOK;
261}
262
[49a796f1]263errno_t async_create_port(iface_t iface, async_port_handler_t handler,
264 void *data, port_id_t *port_id)
265{
266 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
267 return EINVAL;
268
269 return async_create_port_internal(iface, handler, data, port_id);
270}
271
272void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
273{
274 assert(handler != NULL);
275
276 fallback_port_handler = handler;
277 fallback_port_data = data;
278}
279
[3951046]280typedef struct {
281 iface_t iface;
282 interface_t *interface;
283} find_if_port_t;
[49a796f1]284
[3951046]285static bool find_if_port(ht_link_t *link, void *arg)
286{
287 find_if_port_t *fip = (find_if_port_t *)arg;
288 port_t *port;
289 interface_t *interface;
[49a796f1]290
[3951046]291 (void)arg;
292 port = hash_table_get_inst(link, port_t, link);
[49a796f1]293
[3951046]294 ht_link_t *ilink = hash_table_find(&port->interface_hash_table,
295 &fip->iface);
296 if (ilink) {
297 interface = hash_table_get_inst(ilink, interface_t,
298 link);
299 fip->interface = interface;
300 return false;
[49a796f1]301 }
302
[3951046]303 return true;
304}
[49a796f1]305
[3951046]306static interface_t *async_find_interface(iface_t iface, port_id_t port_id)
307{
308 interface_t *interface = NULL;
309 find_if_port_t fip;
310
311 (void)port_id; // XXX !!!
312
313 fibril_rmutex_lock(&port_mutex);
314
315 /*
316 * XXX Find any port implementing that interface. In reality we should
317 * only look at port with ID port_id - but server.c does not
318 * provide us with a correct port ID
319 */
320
321 fip.iface = iface;
322 fip.interface = NULL;
323 hash_table_apply(&port_hash_table, find_if_port, (void *)&fip);
324 interface = fip.interface;
325
326 fibril_rmutex_unlock(&port_mutex);
327 return interface;
[49a796f1]328}
329
[3951046]330async_port_handler_t async_get_interface_handler(iface_t iface,
331 port_id_t port_id, void **data)
[49a796f1]332{
333 assert(data);
334
335 async_port_handler_t handler = fallback_port_handler;
336 *data = fallback_port_data;
337
[3951046]338 interface_t *interface = async_find_interface(iface, port_id);
339 if (interface != NULL) {
340 handler = interface->handler;
341 *data = interface->data;
[49a796f1]342 }
343
344 return handler;
345}
346
[ca48672]347void async_port_destroy(port_id_t port_id)
348{
349 ht_link_t *link;
350 port_t *port;
351
352 fibril_rmutex_lock(&port_mutex);
353 link = hash_table_find(&port_hash_table, &port_id);
354 assert(link != NULL);
355 port = hash_table_get_inst(link, port_t, link);
356 async_delete_port(port);
357 fibril_rmutex_unlock(&port_mutex);
358}
359
[3951046]360/** Initialize the async framework ports.
[49a796f1]361 *
362 */
363void __async_ports_init(void)
364{
[3951046]365 if (fibril_rmutex_initialize(&port_mutex) != EOK)
[45c8eea]366 abort();
367
[3951046]368 if (!hash_table_create(&port_hash_table, 0, 0, &port_hash_table_ops))
[49a796f1]369 abort();
370}
[25f6bddb]371
372void __async_ports_fini(void)
373{
[3951046]374 fibril_rmutex_destroy(&port_mutex);
[25f6bddb]375}
Note: See TracBrowser for help on using the repository browser.