2 * Copyright (c) 2006 Ondrej Palkovsky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
32 #include "../private/async.h"
36 #include <ipc/event.h>
38 #include <adt/hash_table.h>
51 #include <abi/mm/as.h>
52 #include "../private/libc.h"
53 #include "../private/fibril.h"
62 /** Interface ports */
63 hash_table_t port_hash_table
;
65 /** Next available port ID */
66 port_id_t port_id_avail
;
76 /** Port connection handler */
77 async_port_handler_t handler
;
83 /** Default fallback fibril function.
85 * This fallback fibril function gets called on incomming connections that do
86 * not have a specific handler defined.
88 * @param call Data of the incoming call.
89 * @param arg Local argument
92 static void default_fallback_port_handler(ipc_call_t
*call
, void *arg
)
94 async_answer_0(call
, ENOENT
);
97 static async_port_handler_t fallback_port_handler
=
98 default_fallback_port_handler
;
99 static void *fallback_port_data
= NULL
;
101 /** Futex guarding the interface hash table. */
102 static FIBRIL_RMUTEX_INITIALIZE(interface_mutex
);
103 static hash_table_t interface_hash_table
;
105 static size_t interface_key_hash(void *key
)
107 iface_t iface
= *(iface_t
*) key
;
111 static size_t interface_hash(const ht_link_t
*item
)
113 interface_t
*interface
= hash_table_get_inst(item
, interface_t
, link
);
114 return interface_key_hash(&interface
->iface
);
117 static bool interface_key_equal(void *key
, const ht_link_t
*item
)
119 iface_t iface
= *(iface_t
*) key
;
120 interface_t
*interface
= hash_table_get_inst(item
, interface_t
, link
);
121 return iface
== interface
->iface
;
124 /** Operations for the port hash table. */
125 static hash_table_ops_t interface_hash_table_ops
= {
126 .hash
= interface_hash
,
127 .key_hash
= interface_key_hash
,
128 .key_equal
= interface_key_equal
,
130 .remove_callback
= NULL
133 static size_t port_key_hash(void *key
)
135 port_id_t port_id
= *(port_id_t
*) key
;
139 static size_t port_hash(const ht_link_t
*item
)
141 port_t
*port
= hash_table_get_inst(item
, port_t
, link
);
142 return port_key_hash(&port
->id
);
145 static bool port_key_equal(void *key
, const ht_link_t
*item
)
147 port_id_t port_id
= *(port_id_t
*) key
;
148 port_t
*port
= hash_table_get_inst(item
, port_t
, link
);
149 return port_id
== port
->id
;
152 /** Operations for the port hash table. */
153 static hash_table_ops_t port_hash_table_ops
= {
155 .key_hash
= port_key_hash
,
156 .key_equal
= port_key_equal
,
158 .remove_callback
= NULL
161 static interface_t
*async_new_interface(iface_t iface
)
163 interface_t
*interface
=
164 (interface_t
*) malloc(sizeof(interface_t
));
168 bool ret
= hash_table_create(&interface
->port_hash_table
, 0, 0,
169 &port_hash_table_ops
);
175 interface
->iface
= iface
;
176 interface
->port_id_avail
= 0;
178 hash_table_insert(&interface_hash_table
, &interface
->link
);
183 static port_t
*async_new_port(interface_t
*interface
,
184 async_port_handler_t handler
, void *data
)
186 // TODO: Move the malloc out of critical section.
187 port_t
*port
= (port_t
*) malloc(sizeof(port_t
));
191 port_id_t id
= interface
->port_id_avail
;
192 interface
->port_id_avail
++;
195 port
->handler
= handler
;
198 hash_table_insert(&interface
->port_hash_table
, &port
->link
);
203 errno_t
async_create_port_internal(iface_t iface
, async_port_handler_t handler
,
204 void *data
, port_id_t
*port_id
)
206 interface_t
*interface
;
208 fibril_rmutex_lock(&interface_mutex
);
210 ht_link_t
*link
= hash_table_find(&interface_hash_table
, &iface
);
212 interface
= hash_table_get_inst(link
, interface_t
, link
);
214 interface
= async_new_interface(iface
);
217 fibril_rmutex_unlock(&interface_mutex
);
221 port_t
*port
= async_new_port(interface
, handler
, data
);
223 fibril_rmutex_unlock(&interface_mutex
);
229 fibril_rmutex_unlock(&interface_mutex
);
234 errno_t
async_create_port(iface_t iface
, async_port_handler_t handler
,
235 void *data
, port_id_t
*port_id
)
237 if ((iface
& IFACE_MOD_MASK
) == IFACE_MOD_CALLBACK
)
240 return async_create_port_internal(iface
, handler
, data
, port_id
);
243 void async_set_fallback_port_handler(async_port_handler_t handler
, void *data
)
245 assert(handler
!= NULL
);
247 fallback_port_handler
= handler
;
248 fallback_port_data
= data
;
251 static port_t
*async_find_port(iface_t iface
, port_id_t port_id
)
255 fibril_rmutex_lock(&interface_mutex
);
257 ht_link_t
*link
= hash_table_find(&interface_hash_table
, &iface
);
259 interface_t
*interface
=
260 hash_table_get_inst(link
, interface_t
, link
);
262 link
= hash_table_find(&interface
->port_hash_table
, &port_id
);
264 port
= hash_table_get_inst(link
, port_t
, link
);
267 fibril_rmutex_unlock(&interface_mutex
);
272 async_port_handler_t
async_get_port_handler(iface_t iface
, port_id_t port_id
,
277 async_port_handler_t handler
= fallback_port_handler
;
278 *data
= fallback_port_data
;
280 port_t
*port
= async_find_port(iface
, port_id
);
282 handler
= port
->handler
;
289 /** Initialize the async framework.
292 void __async_ports_init(void)
294 if (!hash_table_create(&interface_hash_table
, 0, 0,
295 &interface_hash_table_ops
))