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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since acf6b55 was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 7.1 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
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 <sys/time.h>
44#include <libarch/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
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. */
101static futex_t interface_futex = FUTEX_INITIALIZER;
[49a796f1]102static hash_table_t interface_hash_table;
103
104static size_t interface_key_hash(void *key)
105{
106 iface_t iface = *(iface_t *) 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(void *key, const ht_link_t *item)
117{
118 iface_t iface = *(iface_t *) 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 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(void *key)
133{
134 port_id_t port_id = *(port_id_t *) 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(void *key, const ht_link_t *item)
145{
146 port_id_t port_id = *(port_id_t *) 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 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(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
[5c76cc61]207 futex_lock(&interface_futex);
[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) {
[5c76cc61]216 futex_unlock(&interface_futex);
[49a796f1]217 return ENOMEM;
218 }
219
220 port_t *port = async_new_port(interface, handler, data);
221 if (!port) {
[5c76cc61]222 futex_unlock(&interface_futex);
[49a796f1]223 return ENOMEM;
224 }
225
226 *port_id = port->id;
227
[5c76cc61]228 futex_unlock(&interface_futex);
[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
[5c76cc61]254 futex_lock(&interface_futex);
[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
[5c76cc61]266 futex_unlock(&interface_futex);
[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{
293 if (!hash_table_create(&interface_hash_table, 0, 0,
294 &interface_hash_table_ops))
295 abort();
296}
Note: See TracBrowser for help on using the repository browser.