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

Last change on this file since 3951046 was 3951046, checked in by Jiri Svoboda <jiri@…>, 6 months ago

Async ports and interfaces do the castling.

Now interfaces hang under ports.
Minimum change, missing port ID to select port if iface type is the
same.

  • Property mode set to 100644
File size: 7.8 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
199errno_t async_create_port_internal(iface_t iface, async_port_handler_t handler,
200 void *data, port_id_t *port_id)
201{
202 interface_t *interface;
203
204 fibril_rmutex_lock(&port_mutex);
205
206 port_t *port = async_new_port();
207 if (port == NULL) {
208 fibril_rmutex_unlock(&port_mutex);
209 return ENOMEM;
210 }
211
212 interface = async_new_interface(port, iface, handler, data);
213 if (interface == NULL) {
214 // XXX delete port
215 fibril_rmutex_unlock(&port_mutex);
216 return ENOMEM;
217 }
218
219 *port_id = port->id;
220 fibril_rmutex_unlock(&port_mutex);
221 return EOK;
222}
223
224errno_t async_create_port(iface_t iface, async_port_handler_t handler,
225 void *data, port_id_t *port_id)
226{
227 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
228 return EINVAL;
229
230 return async_create_port_internal(iface, handler, data, port_id);
231}
232
233void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
234{
235 assert(handler != NULL);
236
237 fallback_port_handler = handler;
238 fallback_port_data = data;
239}
240
241typedef struct {
242 iface_t iface;
243 interface_t *interface;
244} find_if_port_t;
245
246static bool find_if_port(ht_link_t *link, void *arg)
247{
248 find_if_port_t *fip = (find_if_port_t *)arg;
249 port_t *port;
250 interface_t *interface;
251
252 (void)arg;
253 port = hash_table_get_inst(link, port_t, link);
254
255 ht_link_t *ilink = hash_table_find(&port->interface_hash_table,
256 &fip->iface);
257 if (ilink) {
258 interface = hash_table_get_inst(ilink, interface_t,
259 link);
260 fip->interface = interface;
261 return false;
262 }
263
264 return true;
265}
266
267static interface_t *async_find_interface(iface_t iface, port_id_t port_id)
268{
269 interface_t *interface = NULL;
270 find_if_port_t fip;
271
272 (void)port_id; // XXX !!!
273
274 fibril_rmutex_lock(&port_mutex);
275
276 /*
277 * XXX Find any port implementing that interface. In reality we should
278 * only look at port with ID port_id - but server.c does not
279 * provide us with a correct port ID
280 */
281
282 fip.iface = iface;
283 fip.interface = NULL;
284 hash_table_apply(&port_hash_table, find_if_port, (void *)&fip);
285 interface = fip.interface;
286
287 fibril_rmutex_unlock(&port_mutex);
288 return interface;
289}
290
291async_port_handler_t async_get_interface_handler(iface_t iface,
292 port_id_t port_id, void **data)
293{
294 assert(data);
295
296 async_port_handler_t handler = fallback_port_handler;
297 *data = fallback_port_data;
298
299 interface_t *interface = async_find_interface(iface, port_id);
300 if (interface != NULL) {
301 handler = interface->handler;
302 *data = interface->data;
303 }
304
305 return handler;
306}
307
308/** Initialize the async framework ports.
309 *
310 */
311void __async_ports_init(void)
312{
313 if (fibril_rmutex_initialize(&port_mutex) != EOK)
314 abort();
315
316 if (!hash_table_create(&port_hash_table, 0, 0, &port_hash_table_ops))
317 abort();
318}
319
320void __async_ports_fini(void)
321{
322 fibril_rmutex_destroy(&port_mutex);
323}
Note: See TracBrowser for help on using the repository browser.