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

Last change on this file since c7c6afd was 0db0df2, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 months ago

Hash table improvements

Implement hash_table_foreach macro, analogous to list_foreach.

Remove superfluous argument to hash_table_find_next().
(If the user needs to recheck the part of the list already
checked by hash_table_find(), they can just rerun that function.)

Add hash argument to hash_table_ops_t::key_equal.
The big change here is that users with big keys can store the hash
value alongside key in their entries, and for the low low cost of
sizeof(size_t) bytes eliminate a bunch of expensive key comparisons.

Also added a hash function for strings and arbitrary data.
Found this one by asking ChatGPT, because the latency of accesses
to my book collection is currently a couple of hours.

+ Some drive-by unused #include removal.

  • Property mode set to 100644
File size: 7.4 KB
RevLine 
[49a796f1]1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[4805495]29#define _LIBC_ASYNC_C_
[49a796f1]30#include <ipc/ipc.h>
31#include <async.h>
32#include "../private/async.h"
[4805495]33#undef _LIBC_ASYNC_C_
[49a796f1]34
35#include <ipc/irq.h>
36#include <ipc/event.h>
37#include <fibril.h>
38#include <adt/hash_table.h>
39#include <adt/hash.h>
40#include <adt/list.h>
41#include <assert.h>
42#include <errno.h>
[bd41ac52]43#include <time.h>
[05882233]44#include <barrier.h>
[49a796f1]45#include <stdbool.h>
46#include <stdlib.h>
47#include <mem.h>
48#include <stdlib.h>
49#include <macros.h>
50#include <as.h>
51#include <abi/mm/as.h>
[f787c8e]52#include "../private/fibril.h"
[49a796f1]53
54/** Interface data */
55typedef struct {
56 ht_link_t link;
57
58 /** Interface ID */
59 iface_t iface;
60
61 /** Interface ports */
62 hash_table_t port_hash_table;
63
64 /** Next available port ID */
65 port_id_t port_id_avail;
66} interface_t;
67
68/* Port data */
69typedef struct {
70 ht_link_t link;
71
72 /** Port ID */
73 port_id_t id;
74
75 /** Port connection handler */
76 async_port_handler_t handler;
77
78 /** Client data */
79 void *data;
80} port_t;
81
82/** Default fallback fibril function.
83 *
84 * This fallback fibril function gets called on incomming connections that do
85 * not have a specific handler defined.
86 *
[984a9ba]87 * @param call Data of the incoming call.
88 * @param arg Local argument
[49a796f1]89 *
90 */
[984a9ba]91static void default_fallback_port_handler(ipc_call_t *call, void *arg)
[49a796f1]92{
[984a9ba]93 async_answer_0(call, ENOENT);
[49a796f1]94}
95
96static async_port_handler_t fallback_port_handler =
97 default_fallback_port_handler;
98static void *fallback_port_data = NULL;
99
[5c76cc61]100/** Futex guarding the interface hash table. */
[45c8eea]101static fibril_rmutex_t interface_mutex;
[49a796f1]102static hash_table_t interface_hash_table;
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
160static interface_t *async_new_interface(iface_t iface)
161{
162 interface_t *interface =
163 (interface_t *) malloc(sizeof(interface_t));
164 if (!interface)
165 return NULL;
166
167 bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
168 &port_hash_table_ops);
169 if (!ret) {
170 free(interface);
171 return NULL;
172 }
173
174 interface->iface = iface;
175 interface->port_id_avail = 0;
176
177 hash_table_insert(&interface_hash_table, &interface->link);
178
179 return interface;
180}
181
182static port_t *async_new_port(interface_t *interface,
183 async_port_handler_t handler, void *data)
184{
[5c76cc61]185 // TODO: Move the malloc out of critical section.
[49a796f1]186 port_t *port = (port_t *) malloc(sizeof(port_t));
187 if (!port)
188 return NULL;
189
190 port_id_t id = interface->port_id_avail;
191 interface->port_id_avail++;
192
193 port->id = id;
194 port->handler = handler;
195 port->data = data;
196
197 hash_table_insert(&interface->port_hash_table, &port->link);
198
199 return port;
200}
201
202errno_t async_create_port_internal(iface_t iface, async_port_handler_t handler,
203 void *data, port_id_t *port_id)
204{
205 interface_t *interface;
206
[9bde0d5]207 fibril_rmutex_lock(&interface_mutex);
[49a796f1]208
209 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
210 if (link)
211 interface = hash_table_get_inst(link, interface_t, link);
212 else
213 interface = async_new_interface(iface);
214
215 if (!interface) {
[9bde0d5]216 fibril_rmutex_unlock(&interface_mutex);
[49a796f1]217 return ENOMEM;
218 }
219
220 port_t *port = async_new_port(interface, handler, data);
221 if (!port) {
[9bde0d5]222 fibril_rmutex_unlock(&interface_mutex);
[49a796f1]223 return ENOMEM;
224 }
225
226 *port_id = port->id;
227
[9bde0d5]228 fibril_rmutex_unlock(&interface_mutex);
[49a796f1]229
230 return EOK;
231}
232
233errno_t async_create_port(iface_t iface, async_port_handler_t handler,
234 void *data, port_id_t *port_id)
235{
236 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
237 return EINVAL;
238
239 return async_create_port_internal(iface, handler, data, port_id);
240}
241
242void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
243{
244 assert(handler != NULL);
245
246 fallback_port_handler = handler;
247 fallback_port_data = data;
248}
249
250static port_t *async_find_port(iface_t iface, port_id_t port_id)
251{
252 port_t *port = NULL;
253
[9bde0d5]254 fibril_rmutex_lock(&interface_mutex);
[49a796f1]255
256 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
257 if (link) {
258 interface_t *interface =
259 hash_table_get_inst(link, interface_t, link);
260
261 link = hash_table_find(&interface->port_hash_table, &port_id);
262 if (link)
263 port = hash_table_get_inst(link, port_t, link);
264 }
265
[9bde0d5]266 fibril_rmutex_unlock(&interface_mutex);
[49a796f1]267
268 return port;
269}
270
271async_port_handler_t async_get_port_handler(iface_t iface, port_id_t port_id,
272 void **data)
273{
274 assert(data);
275
276 async_port_handler_t handler = fallback_port_handler;
277 *data = fallback_port_data;
278
279 port_t *port = async_find_port(iface, port_id);
280 if (port) {
281 handler = port->handler;
282 *data = port->data;
283 }
284
285 return handler;
286}
287
288/** Initialize the async framework.
289 *
290 */
291void __async_ports_init(void)
292{
[45c8eea]293 if (fibril_rmutex_initialize(&interface_mutex) != EOK)
294 abort();
295
[49a796f1]296 if (!hash_table_create(&interface_hash_table, 0, 0,
297 &interface_hash_table_ops))
298 abort();
299}
[25f6bddb]300
301void __async_ports_fini(void)
302{
303 fibril_rmutex_destroy(&interface_mutex);
304}
Note: See TracBrowser for help on using the repository browser.