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@…>, 8 days ago

Fix missing argument when destroying async port.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * Copyright (c) 2025 Jiri Svoboda
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
30#define _LIBC_ASYNC_C_
31#include <ipc/ipc.h>
32#include <async.h>
33#include "../private/async.h"
34#undef _LIBC_ASYNC_C_
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>
44#include <time.h>
45#include <barrier.h>
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>
53#include "../private/fibril.h"
54
55/** Interface data */
56typedef struct {
57 ht_link_t link;
58
59 /** Interface ID */
60 iface_t iface;
61
62 /** Interface connection handler */
63 async_port_handler_t handler;
64
65 /** Client data */
66 void *data;
67} interface_t;
68
69/* Port data */
70typedef struct {
71 ht_link_t link;
72
73 /** Port ID */
74 port_id_t id;
75
76 /** Port interfaces */
77 hash_table_t interface_hash_table;
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 *
85 * @param call Data of the incoming call.
86 * @param arg Local argument
87 *
88 */
89static void default_fallback_port_handler(ipc_call_t *call, void *arg)
90{
91 async_answer_0(call, ENOENT);
92}
93
94static async_port_handler_t fallback_port_handler =
95 default_fallback_port_handler;
96static void *fallback_port_data = NULL;
97
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;
103
104static size_t interface_key_hash(const void *key)
105{
106 const iface_t *iface = key;
107 return *iface;
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
116static bool interface_key_equal(const void *key, size_t hash, const ht_link_t *item)
117{
118 const iface_t *iface = key;
119 interface_t *interface = hash_table_get_inst(item, interface_t, link);
120 return *iface == interface->iface;
121}
122
123/** Operations for the port hash table. */
124static const hash_table_ops_t interface_hash_table_ops = {
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
132static size_t port_key_hash(const void *key)
133{
134 const port_id_t *port_id = key;
135 return *port_id;
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
144static bool port_key_equal(const void *key, size_t hash, const ht_link_t *item)
145{
146 const port_id_t *port_id = key;
147 port_t *port = hash_table_get_inst(item, port_t, link);
148 return *port_id == port->id;
149}
150
151/** Operations for the port hash table. */
152static const hash_table_ops_t port_hash_table_ops = {
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
160static interface_t *async_new_interface(port_t *port, iface_t iface,
161 async_port_handler_t handler, void *data)
162{
163 interface_t *interface =
164 (interface_t *) malloc(sizeof(interface_t));
165 if (!interface)
166 return NULL;
167 interface->iface = iface;
168 interface->handler = handler;
169 interface->data = data;
170
171 hash_table_insert(&port->interface_hash_table, &interface->link);
172
173 return interface;
174}
175
176static port_t *async_new_port(void)
177{
178 // TODO: Move the malloc out of critical section.
179 port_t *port = (port_t *) malloc(sizeof(port_t));
180 if (!port)
181 return NULL;
182
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 }
189
190 port_id_t id = port_id_avail;
191 port_id_avail++;
192
193 port->id = id;
194 hash_table_insert(&port_hash_table, &port->link);
195
196 return port;
197}
198
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 */
210 hash_table_apply(&port->interface_hash_table, destroy_if, port);
211
212 hash_table_destroy(&port->interface_hash_table);
213 free(port);
214}
215
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
221 fibril_rmutex_lock(&port_mutex);
222
223 port_t *port = async_new_port();
224 if (port == NULL) {
225 fibril_rmutex_unlock(&port_mutex);
226 return ENOMEM;
227 }
228
229 interface = async_new_interface(port, iface, handler, data);
230 if (interface == NULL) {
231 async_delete_port(port);
232 fibril_rmutex_unlock(&port_mutex);
233 return ENOMEM;
234 }
235
236 *port_id = port->id;
237 fibril_rmutex_unlock(&port_mutex);
238 return EOK;
239}
240
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
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
280typedef struct {
281 iface_t iface;
282 interface_t *interface;
283} find_if_port_t;
284
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;
290
291 (void)arg;
292 port = hash_table_get_inst(link, port_t, link);
293
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;
301 }
302
303 return true;
304}
305
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;
328}
329
330async_port_handler_t async_get_interface_handler(iface_t iface,
331 port_id_t port_id, void **data)
332{
333 assert(data);
334
335 async_port_handler_t handler = fallback_port_handler;
336 *data = fallback_port_data;
337
338 interface_t *interface = async_find_interface(iface, port_id);
339 if (interface != NULL) {
340 handler = interface->handler;
341 *data = interface->data;
342 }
343
344 return handler;
345}
346
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
360/** Initialize the async framework ports.
361 *
362 */
363void __async_ports_init(void)
364{
365 if (fibril_rmutex_initialize(&port_mutex) != EOK)
366 abort();
367
368 if (!hash_table_create(&port_hash_table, 0, 0, &port_hash_table_ops))
369 abort();
370}
371
372void __async_ports_fini(void)
373{
374 fibril_rmutex_destroy(&port_mutex);
375}
Note: See TracBrowser for help on using the repository browser.