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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9f272d9 was 49a796f1, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Split the async framework into several parts.

This segregates existing code into three separate files,
to make the async framework easier to navigate and understand.

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