source: mainline/uspace/srv/ns/service.c@ e2f332c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e2f332c was 4f13e19, checked in by GitHub <noreply@…>, 7 years ago

Remove async "fast" and "slow" functions from public interface (#153)

"fast" and "slow" paths are implementation detail.
All macros in <async.h> are turned into external functions, so that
this implementation detail doesn't leak. Additionally, removing macros is
A Good Thing on its own, e.g. helping C++ interoperability.

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2009 Martin Decky
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/** @addtogroup ns
30 * @{
31 */
32
33#include <adt/hash_table.h>
34#include <assert.h>
35#include <async.h>
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include "service.h"
40#include "ns.h"
41
42/** Service hash table item. */
43typedef struct {
44 ht_link_t link;
45
46 /** Service ID */
47 service_t service;
48
49 /** Interface hash table */
50 hash_table_t iface_hash_table;
51
52 /** Broker session to the service */
53 async_sess_t *broker_sess;
54} hashed_service_t;
55
56/** Interface hash table item. */
57typedef struct {
58 ht_link_t link;
59
60 /** Interface ID */
61 iface_t iface;
62
63 /** Session to the service */
64 async_sess_t *sess;
65} hashed_iface_t;
66
67static size_t service_key_hash(void *key)
68{
69 return *(service_t *) key;
70}
71
72static size_t service_hash(const ht_link_t *item)
73{
74 hashed_service_t *service =
75 hash_table_get_inst(item, hashed_service_t, link);
76
77 return service->service;
78}
79
80static bool service_key_equal(void *key, const ht_link_t *item)
81{
82 hashed_service_t *service =
83 hash_table_get_inst(item, hashed_service_t, link);
84
85 return service->service == *(service_t *) key;
86}
87
88static size_t iface_key_hash(void *key)
89{
90 return *(iface_t *) key;
91}
92
93static size_t iface_hash(const ht_link_t *item)
94{
95 hashed_iface_t *iface =
96 hash_table_get_inst(item, hashed_iface_t, link);
97
98 return iface->iface;
99}
100
101static bool iface_key_equal(void *key, const ht_link_t *item)
102{
103 hashed_iface_t *iface =
104 hash_table_get_inst(item, hashed_iface_t, link);
105
106 return iface->iface == *(iface_t *) key;
107}
108
109/** Operations for service hash table. */
110static hash_table_ops_t service_hash_table_ops = {
111 .hash = service_hash,
112 .key_hash = service_key_hash,
113 .key_equal = service_key_equal,
114 .equal = NULL,
115 .remove_callback = NULL
116};
117
118/** Operations for interface hash table. */
119static hash_table_ops_t iface_hash_table_ops = {
120 .hash = iface_hash,
121 .key_hash = iface_key_hash,
122 .key_equal = iface_key_equal,
123 .equal = NULL,
124 .remove_callback = NULL
125};
126
127/** Service hash table structure. */
128static hash_table_t service_hash_table;
129
130/** Pending connection structure. */
131typedef struct {
132 link_t link;
133 service_t service; /**< Service ID */
134 iface_t iface; /**< Interface ID */
135 ipc_call_t call; /**< Call waiting for the connection */
136} pending_conn_t;
137
138static list_t pending_conn;
139
140errno_t ns_service_init(void)
141{
142 if (!hash_table_create(&service_hash_table, 0, 0,
143 &service_hash_table_ops)) {
144 printf("%s: No memory available for services\n", NAME);
145 return ENOMEM;
146 }
147
148 list_initialize(&pending_conn);
149
150 return EOK;
151}
152
153static void ns_forward(async_sess_t *sess, ipc_call_t *call, iface_t iface)
154{
155 async_exch_t *exch = async_exchange_begin(sess);
156 async_forward_1(call, exch, iface, IPC_GET_ARG3(*call), IPC_FF_NONE);
157 async_exchange_end(exch);
158}
159
160/** Process pending connection requests */
161void ns_pending_conn_process(void)
162{
163loop:
164 list_foreach(pending_conn, link, pending_conn_t, pending) {
165 ht_link_t *link =
166 hash_table_find(&service_hash_table, &pending->service);
167 if (!link)
168 continue;
169
170 hashed_service_t *hashed_service =
171 hash_table_get_inst(link, hashed_service_t, link);
172
173 link = hash_table_find(&hashed_service->iface_hash_table,
174 &pending->iface);
175 if (!link) {
176 if (hashed_service->broker_sess != NULL) {
177 ns_forward(hashed_service->broker_sess, &pending->call,
178 pending->iface);
179
180 list_remove(&pending->link);
181 free(pending);
182
183 goto loop;
184 }
185
186 continue;
187 }
188
189 hashed_iface_t *hashed_iface =
190 hash_table_get_inst(link, hashed_iface_t, link);
191
192 ns_forward(hashed_iface->sess, &pending->call, pending->iface);
193
194 list_remove(&pending->link);
195 free(pending);
196
197 goto loop;
198 }
199}
200
201/** Register interface to a service.
202 *
203 * @param service Service to which the interface belongs.
204 * @param iface Interface to be registered.
205 *
206 * @return Zero on success or a value from @ref errno.h.
207 *
208 */
209static errno_t ns_iface_register(hashed_service_t *hashed_service, iface_t iface)
210{
211 ht_link_t *link = hash_table_find(&hashed_service->iface_hash_table,
212 &iface);
213 if (link)
214 return EEXIST;
215
216 hashed_iface_t *hashed_iface =
217 (hashed_iface_t *) malloc(sizeof(hashed_iface_t));
218 if (!hashed_iface)
219 return ENOMEM;
220
221 hashed_iface->iface = iface;
222 hashed_iface->sess = async_callback_receive(EXCHANGE_SERIALIZE);
223 if (hashed_iface->sess == NULL) {
224 free(hashed_iface);
225 return EIO;
226 }
227
228 hash_table_insert(&hashed_service->iface_hash_table,
229 &hashed_iface->link);
230 return EOK;
231}
232
233/** Register broker to a service.
234 *
235 * @param service Service to which the broker belongs.
236 *
237 * @return Zero on success or a value from @ref errno.h.
238 *
239 */
240static errno_t ns_broker_register(hashed_service_t *hashed_service)
241{
242 if (hashed_service->broker_sess != NULL)
243 return EEXIST;
244
245 hashed_service->broker_sess = async_callback_receive(EXCHANGE_SERIALIZE);
246 if (hashed_service->broker_sess == NULL)
247 return EIO;
248
249 return EOK;
250}
251
252/** Register service.
253 *
254 * @param service Service to be registered.
255 * @param iface Interface to be registered.
256 *
257 * @return Zero on success or a value from @ref errno.h.
258 *
259 */
260errno_t ns_service_register(service_t service, iface_t iface)
261{
262 ht_link_t *link = hash_table_find(&service_hash_table, &service);
263
264 if (link) {
265 hashed_service_t *hashed_service =
266 hash_table_get_inst(link, hashed_service_t, link);
267
268 assert(hashed_service->service == service);
269
270 return ns_iface_register(hashed_service, iface);
271 }
272
273 hashed_service_t *hashed_service =
274 (hashed_service_t *) malloc(sizeof(hashed_service_t));
275 if (!hashed_service)
276 return ENOMEM;
277
278 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
279 &iface_hash_table_ops)) {
280 free(hashed_service);
281 return ENOMEM;
282 }
283
284 hashed_service->broker_sess = NULL;
285 hashed_service->service = service;
286 errno_t rc = ns_iface_register(hashed_service, iface);
287 if (rc != EOK) {
288 free(hashed_service);
289 return rc;
290 }
291
292 hash_table_insert(&service_hash_table, &hashed_service->link);
293 return EOK;
294}
295
296/** Register broker service.
297 *
298 * @param service Broker service to be registered.
299 *
300 * @return Zero on success or a value from @ref errno.h.
301 *
302 */
303errno_t ns_service_register_broker(service_t service)
304{
305 ht_link_t *link = hash_table_find(&service_hash_table, &service);
306
307 if (link) {
308 hashed_service_t *hashed_service =
309 hash_table_get_inst(link, hashed_service_t, link);
310
311 assert(hashed_service->service == service);
312
313 return ns_broker_register(hashed_service);
314 }
315
316 hashed_service_t *hashed_service =
317 (hashed_service_t *) malloc(sizeof(hashed_service_t));
318 if (!hashed_service)
319 return ENOMEM;
320
321 if (!hash_table_create(&hashed_service->iface_hash_table, 0, 0,
322 &iface_hash_table_ops)) {
323 free(hashed_service);
324 return ENOMEM;
325 }
326
327 hashed_service->broker_sess = NULL;
328 hashed_service->service = service;
329 errno_t rc = ns_broker_register(hashed_service);
330 if (rc != EOK) {
331 free(hashed_service);
332 return rc;
333 }
334
335 hash_table_insert(&service_hash_table, &hashed_service->link);
336 return EOK;
337}
338
339/** Add pending connection */
340static errno_t ns_pending_conn_add(service_t service, iface_t iface,
341 ipc_call_t *call)
342{
343 pending_conn_t *pending =
344 (pending_conn_t *) malloc(sizeof(pending_conn_t));
345 if (!pending)
346 return ENOMEM;
347
348 link_initialize(&pending->link);
349 pending->service = service;
350 pending->iface = iface;
351 pending->call = *call;
352
353 list_append(&pending->link, &pending_conn);
354 return EOK;
355}
356
357/** Connect client to service.
358 *
359 * @param service Service to be connected to.
360 * @param iface Interface to be connected to.
361 * @param call Pointer to call structure.
362 *
363 * @return Zero on success or a value from @ref errno.h.
364 *
365 */
366void ns_service_forward(service_t service, iface_t iface, ipc_call_t *call)
367{
368 sysarg_t flags = IPC_GET_ARG4(*call);
369 errno_t retval;
370
371 ht_link_t *link = hash_table_find(&service_hash_table, &service);
372 if (!link) {
373 if (flags & IPC_FLAG_BLOCKING) {
374 /* Blocking connection, add to pending list */
375 errno_t rc = ns_pending_conn_add(service, iface, call);
376 if (rc == EOK)
377 return;
378
379 retval = rc;
380 goto out;
381 }
382
383 retval = ENOENT;
384 goto out;
385 }
386
387 hashed_service_t *hashed_service =
388 hash_table_get_inst(link, hashed_service_t, link);
389
390 link = hash_table_find(&hashed_service->iface_hash_table, &iface);
391 if (!link) {
392 if (hashed_service->broker_sess != NULL) {
393 ns_forward(hashed_service->broker_sess, call, iface);
394 return;
395 }
396
397 if (flags & IPC_FLAG_BLOCKING) {
398 /* Blocking connection, add to pending list */
399 errno_t rc = ns_pending_conn_add(service, iface, call);
400 if (rc == EOK)
401 return;
402
403 retval = rc;
404 goto out;
405 }
406
407 retval = ENOENT;
408 goto out;
409 }
410
411 hashed_iface_t *hashed_iface =
412 hash_table_get_inst(link, hashed_iface_t, link);
413
414 ns_forward(hashed_iface->sess, call, iface);
415 return;
416
417out:
418 async_answer_0(call, retval);
419}
420
421/**
422 * @}
423 */
Note: See TracBrowser for help on using the repository browser.