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

Last change on this file since 241f1985 was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 7.3 KB
Line 
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
29#define _LIBC_ASYNC_C_
30#include <ipc/ipc.h>
31#include <async.h>
32#include "../private/async.h"
33#undef _LIBC_ASYNC_C_
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>
43#include <time.h>
44#include <barrier.h>
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>
52#include "../private/libc.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 ports */
63 hash_table_t port_hash_table;
64
65 /** Next available port ID */
66 port_id_t port_id_avail;
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 connection handler */
77 async_port_handler_t handler;
78
79 /** Client data */
80 void *data;
81} port_t;
82
83/** Default fallback fibril function.
84 *
85 * This fallback fibril function gets called on incomming connections that do
86 * not have a specific handler defined.
87 *
88 * @param call Data of the incoming call.
89 * @param arg Local argument
90 *
91 */
92static void default_fallback_port_handler(ipc_call_t *call, void *arg)
93{
94 async_answer_0(call, ENOENT);
95}
96
97static async_port_handler_t fallback_port_handler =
98 default_fallback_port_handler;
99static void *fallback_port_data = NULL;
100
101/** Futex guarding the interface hash table. */
102static fibril_rmutex_t interface_mutex;
103static hash_table_t interface_hash_table;
104
105static size_t interface_key_hash(const void *key)
106{
107 const iface_t *iface = key;
108 return *iface;
109}
110
111static size_t interface_hash(const ht_link_t *item)
112{
113 interface_t *interface = hash_table_get_inst(item, interface_t, link);
114 return interface_key_hash(&interface->iface);
115}
116
117static bool interface_key_equal(const void *key, const ht_link_t *item)
118{
119 const iface_t *iface = key;
120 interface_t *interface = hash_table_get_inst(item, interface_t, link);
121 return *iface == interface->iface;
122}
123
124/** Operations for the port hash table. */
125static hash_table_ops_t interface_hash_table_ops = {
126 .hash = interface_hash,
127 .key_hash = interface_key_hash,
128 .key_equal = interface_key_equal,
129 .equal = NULL,
130 .remove_callback = NULL
131};
132
133static size_t port_key_hash(const void *key)
134{
135 const port_id_t *port_id = key;
136 return *port_id;
137}
138
139static size_t port_hash(const ht_link_t *item)
140{
141 port_t *port = hash_table_get_inst(item, port_t, link);
142 return port_key_hash(&port->id);
143}
144
145static bool port_key_equal(const void *key, const ht_link_t *item)
146{
147 const port_id_t *port_id = key;
148 port_t *port = hash_table_get_inst(item, port_t, link);
149 return *port_id == port->id;
150}
151
152/** Operations for the port hash table. */
153static hash_table_ops_t port_hash_table_ops = {
154 .hash = port_hash,
155 .key_hash = port_key_hash,
156 .key_equal = port_key_equal,
157 .equal = NULL,
158 .remove_callback = NULL
159};
160
161static interface_t *async_new_interface(iface_t iface)
162{
163 interface_t *interface =
164 (interface_t *) malloc(sizeof(interface_t));
165 if (!interface)
166 return NULL;
167
168 bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
169 &port_hash_table_ops);
170 if (!ret) {
171 free(interface);
172 return NULL;
173 }
174
175 interface->iface = iface;
176 interface->port_id_avail = 0;
177
178 hash_table_insert(&interface_hash_table, &interface->link);
179
180 return interface;
181}
182
183static port_t *async_new_port(interface_t *interface,
184 async_port_handler_t handler, void *data)
185{
186 // TODO: Move the malloc out of critical section.
187 port_t *port = (port_t *) malloc(sizeof(port_t));
188 if (!port)
189 return NULL;
190
191 port_id_t id = interface->port_id_avail;
192 interface->port_id_avail++;
193
194 port->id = id;
195 port->handler = handler;
196 port->data = data;
197
198 hash_table_insert(&interface->port_hash_table, &port->link);
199
200 return port;
201}
202
203errno_t async_create_port_internal(iface_t iface, async_port_handler_t handler,
204 void *data, port_id_t *port_id)
205{
206 interface_t *interface;
207
208 fibril_rmutex_lock(&interface_mutex);
209
210 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
211 if (link)
212 interface = hash_table_get_inst(link, interface_t, link);
213 else
214 interface = async_new_interface(iface);
215
216 if (!interface) {
217 fibril_rmutex_unlock(&interface_mutex);
218 return ENOMEM;
219 }
220
221 port_t *port = async_new_port(interface, handler, data);
222 if (!port) {
223 fibril_rmutex_unlock(&interface_mutex);
224 return ENOMEM;
225 }
226
227 *port_id = port->id;
228
229 fibril_rmutex_unlock(&interface_mutex);
230
231 return EOK;
232}
233
234errno_t async_create_port(iface_t iface, async_port_handler_t handler,
235 void *data, port_id_t *port_id)
236{
237 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
238 return EINVAL;
239
240 return async_create_port_internal(iface, handler, data, port_id);
241}
242
243void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
244{
245 assert(handler != NULL);
246
247 fallback_port_handler = handler;
248 fallback_port_data = data;
249}
250
251static port_t *async_find_port(iface_t iface, port_id_t port_id)
252{
253 port_t *port = NULL;
254
255 fibril_rmutex_lock(&interface_mutex);
256
257 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
258 if (link) {
259 interface_t *interface =
260 hash_table_get_inst(link, interface_t, link);
261
262 link = hash_table_find(&interface->port_hash_table, &port_id);
263 if (link)
264 port = hash_table_get_inst(link, port_t, link);
265 }
266
267 fibril_rmutex_unlock(&interface_mutex);
268
269 return port;
270}
271
272async_port_handler_t async_get_port_handler(iface_t iface, port_id_t port_id,
273 void **data)
274{
275 assert(data);
276
277 async_port_handler_t handler = fallback_port_handler;
278 *data = fallback_port_data;
279
280 port_t *port = async_find_port(iface, port_id);
281 if (port) {
282 handler = port->handler;
283 *data = port->data;
284 }
285
286 return handler;
287}
288
289/** Initialize the async framework.
290 *
291 */
292void __async_ports_init(void)
293{
294 if (fibril_rmutex_initialize(&interface_mutex) != EOK)
295 abort();
296
297 if (!hash_table_create(&interface_hash_table, 0, 0,
298 &interface_hash_table_ops))
299 abort();
300}
301
302void __async_ports_fini(void)
303{
304 fibril_rmutex_destroy(&interface_mutex);
305}
Note: See TracBrowser for help on using the repository browser.