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

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

Remove some unnecessary includes.

  • 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 <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 *
87 * @param chandle Handle of the incoming call.
88 * @param call Data of the incoming call.
89 * @param arg Local argument
90 *
91 */
92static void default_fallback_port_handler(cap_call_handle_t chandle,
93 ipc_call_t *call, void *arg)
94{
95 ipc_answer_0(chandle, ENOENT);
96}
97
98static async_port_handler_t fallback_port_handler =
99 default_fallback_port_handler;
100static void *fallback_port_data = NULL;
101
102/** Futex guarding the interface hash table. */
103static futex_t interface_futex = FUTEX_INITIALIZER;
104static hash_table_t interface_hash_table;
105
106static size_t interface_key_hash(void *key)
107{
108 iface_t iface = *(iface_t *) key;
109 return iface;
110}
111
112static size_t interface_hash(const ht_link_t *item)
113{
114 interface_t *interface = hash_table_get_inst(item, interface_t, link);
115 return interface_key_hash(&interface->iface);
116}
117
118static bool interface_key_equal(void *key, const ht_link_t *item)
119{
120 iface_t iface = *(iface_t *) key;
121 interface_t *interface = hash_table_get_inst(item, interface_t, link);
122 return iface == interface->iface;
123}
124
125/** Operations for the port hash table. */
126static hash_table_ops_t interface_hash_table_ops = {
127 .hash = interface_hash,
128 .key_hash = interface_key_hash,
129 .key_equal = interface_key_equal,
130 .equal = NULL,
131 .remove_callback = NULL
132};
133
134static size_t port_key_hash(void *key)
135{
136 port_id_t port_id = *(port_id_t *) key;
137 return port_id;
138}
139
140static size_t port_hash(const ht_link_t *item)
141{
142 port_t *port = hash_table_get_inst(item, port_t, link);
143 return port_key_hash(&port->id);
144}
145
146static bool port_key_equal(void *key, const ht_link_t *item)
147{
148 port_id_t port_id = *(port_id_t *) key;
149 port_t *port = hash_table_get_inst(item, port_t, link);
150 return port_id == port->id;
151}
152
153/** Operations for the port hash table. */
154static hash_table_ops_t port_hash_table_ops = {
155 .hash = port_hash,
156 .key_hash = port_key_hash,
157 .key_equal = port_key_equal,
158 .equal = NULL,
159 .remove_callback = NULL
160};
161
162static interface_t *async_new_interface(iface_t iface)
163{
164 interface_t *interface =
165 (interface_t *) malloc(sizeof(interface_t));
166 if (!interface)
167 return NULL;
168
169 bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
170 &port_hash_table_ops);
171 if (!ret) {
172 free(interface);
173 return NULL;
174 }
175
176 interface->iface = iface;
177 interface->port_id_avail = 0;
178
179 hash_table_insert(&interface_hash_table, &interface->link);
180
181 return interface;
182}
183
184static port_t *async_new_port(interface_t *interface,
185 async_port_handler_t handler, void *data)
186{
187 // TODO: Move the malloc out of critical section.
188 port_t *port = (port_t *) malloc(sizeof(port_t));
189 if (!port)
190 return NULL;
191
192 port_id_t id = interface->port_id_avail;
193 interface->port_id_avail++;
194
195 port->id = id;
196 port->handler = handler;
197 port->data = data;
198
199 hash_table_insert(&interface->port_hash_table, &port->link);
200
201 return port;
202}
203
204errno_t async_create_port_internal(iface_t iface, async_port_handler_t handler,
205 void *data, port_id_t *port_id)
206{
207 interface_t *interface;
208
209 futex_lock(&interface_futex);
210
211 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
212 if (link)
213 interface = hash_table_get_inst(link, interface_t, link);
214 else
215 interface = async_new_interface(iface);
216
217 if (!interface) {
218 futex_unlock(&interface_futex);
219 return ENOMEM;
220 }
221
222 port_t *port = async_new_port(interface, handler, data);
223 if (!port) {
224 futex_unlock(&interface_futex);
225 return ENOMEM;
226 }
227
228 *port_id = port->id;
229
230 futex_unlock(&interface_futex);
231
232 return EOK;
233}
234
235errno_t async_create_port(iface_t iface, async_port_handler_t handler,
236 void *data, port_id_t *port_id)
237{
238 if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
239 return EINVAL;
240
241 return async_create_port_internal(iface, handler, data, port_id);
242}
243
244void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
245{
246 assert(handler != NULL);
247
248 fallback_port_handler = handler;
249 fallback_port_data = data;
250}
251
252static port_t *async_find_port(iface_t iface, port_id_t port_id)
253{
254 port_t *port = NULL;
255
256 futex_lock(&interface_futex);
257
258 ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
259 if (link) {
260 interface_t *interface =
261 hash_table_get_inst(link, interface_t, link);
262
263 link = hash_table_find(&interface->port_hash_table, &port_id);
264 if (link)
265 port = hash_table_get_inst(link, port_t, link);
266 }
267
268 futex_unlock(&interface_futex);
269
270 return port;
271}
272
273async_port_handler_t async_get_port_handler(iface_t iface, port_id_t port_id,
274 void **data)
275{
276 assert(data);
277
278 async_port_handler_t handler = fallback_port_handler;
279 *data = fallback_port_data;
280
281 port_t *port = async_find_port(iface, port_id);
282 if (port) {
283 handler = port->handler;
284 *data = port->data;
285 }
286
287 return handler;
288}
289
290/** Initialize the async framework.
291 *
292 */
293void __async_ports_init(void)
294{
295 if (!hash_table_create(&interface_hash_table, 0, 0,
296 &interface_hash_table_ops))
297 abort();
298}
Note: See TracBrowser for help on using the repository browser.