source: mainline/uspace/lib/c/generic/async/server.c@ 0a8f070

Last change on this file since 0a8f070 was 0a8f070, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Create taskman server (extracts task-related operations from naming service)

  • Exploits initial phones connected to spawn parent instead of NS.
  • session_ns changed to session_primary (setup during taskman-loader handshake).
  • Task creation moved from NS to taskman (no clonable services anymore).
  • Other task-related operations implementation is to come (task_retval is temporarily dummy).
  • Async framework: implicit connections — create fibrils for calls that arrived through initial phone.

Conflicts:

abi/include/abi/ipc/methods.h
boot/Makefile.common
uspace/Makefile
uspace/app/trace/ipcp.c
uspace/lib/c/generic/async.c
uspace/lib/c/generic/libc.c
uspace/lib/c/generic/loader.c
uspace/lib/c/generic/ns.c
uspace/lib/c/generic/private/async.h
uspace/lib/c/generic/private/ns.h
uspace/lib/c/generic/task.c
uspace/lib/c/include/async.h
uspace/lib/c/include/ipc/services.h
uspace/lib/c/include/ipc/taskman.h
uspace/lib/c/include/loader/pcb.h
uspace/lib/c/include/ns.h
uspace/srv/loader/main.c
uspace/srv/ns/clonable.c
uspace/srv/ns/ns.c

  • Property mode set to 100644
File size: 45.7 KB
RevLine 
[06502f7d]1/*
[df4ed85]2 * Copyright (c) 2006 Ondrej Palkovsky
[06502f7d]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.
[b2951e2]27 */
28
[a46da63]29/** @addtogroup libc
[b2951e2]30 * @{
31 */
32/** @file
[c07544d3]33 */
[06502f7d]34
[80649a91]35/**
36 * Asynchronous library
37 *
[c07544d3]38 * The aim of this library is to provide a facility for writing programs which
39 * utilize the asynchronous nature of HelenOS IPC, yet using a normal way of
40 * programming.
[80649a91]41 *
[79ae36dd]42 * You should be able to write very simple multithreaded programs. The async
43 * framework will automatically take care of most of the synchronization
44 * problems.
[80649a91]45 *
[9591265]46 * Example of use (pseudo C):
[c07544d3]47 *
[80649a91]48 * 1) Multithreaded client application
[9591265]49 *
[c07544d3]50 * fibril_create(fibril1, ...);
51 * fibril_create(fibril2, ...);
52 * ...
53 *
54 * int fibril1(void *arg)
55 * {
[79ae36dd]56 * conn = async_connect_me_to(...);
57 *
58 * exch = async_exchange_begin(conn);
59 * c1 = async_send(exch);
60 * async_exchange_end(exch);
61 *
62 * exch = async_exchange_begin(conn);
63 * c2 = async_send(exch);
64 * async_exchange_end(exch);
65 *
[c07544d3]66 * async_wait_for(c1);
67 * async_wait_for(c2);
68 * ...
69 * }
[80649a91]70 *
71 *
72 * 2) Multithreaded server application
73 *
[c07544d3]74 * main()
75 * {
76 * async_manager();
77 * }
78 *
[984a9ba]79 * port_handler(ipc_call_t *icall)
[c07544d3]80 * {
81 * if (want_refuse) {
[984a9ba]82 * async_answer_0(icall, ELIMIT);
[c07544d3]83 * return;
84 * }
[80649a91]85 *
[984a9ba]86 * async_answer_0(icall, EOK);
[53ca318]87 *
[984a9ba]88 * async_get_call(&call);
89 * somehow_handle_the_call(&call);
90 * async_answer_2(&call, 1, 2, 3);
91 *
92 * async_get_call(&call);
[c07544d3]93 * ...
94 * }
[a2cd194]95 *
[80649a91]96 */
[9591265]97
[4805495]98#define _LIBC_ASYNC_C_
[64d2b10]99#include <ipc/ipc.h>
[80649a91]100#include <async.h>
[49a796f1]101#include "../private/async.h"
[4805495]102#undef _LIBC_ASYNC_C_
[64d2b10]103
[8820544]104#include <ipc/irq.h>
105#include <ipc/event.h>
[bc1f1c2]106#include <fibril.h>
[d9c8c81]107#include <adt/hash_table.h>
[853802e]108#include <adt/hash.h>
[d9c8c81]109#include <adt/list.h>
[80649a91]110#include <assert.h>
111#include <errno.h>
[bd41ac52]112#include <time.h>
[3e6a98c5]113#include <stdbool.h>
[38d150e]114#include <stdlib.h>
[79ae36dd]115#include <mem.h>
116#include <stdlib.h>
[e2ab36f1]117#include <macros.h>
[514d561]118#include <str_error.h>
[101516d]119#include <as.h>
[ae6021d]120#include <abi/mm/as.h>
[49a796f1]121#include "../private/libc.h"
[d73d992]122#include "../private/fibril.h"
[5da7199]123
[8dab988]124#define DPRINTF(...) ((void) 0)
125
[79ae36dd]126/* Client connection data */
[c80fdd0]127typedef struct {
[062d900]128 ht_link_t link;
[a35b458]129
[649f087]130 task_id_t in_task_id;
[498ced1]131 int refcnt;
[c80fdd0]132 void *data;
133} client_t;
134
[79ae36dd]135/* Server connection data */
[80649a91]136typedef struct {
[514d561]137 /** Fibril handling the connection. */
138 fid_t fid;
[a35b458]139
[e70bfa5]140 /** Hash table link. */
[062d900]141 ht_link_t link;
[a35b458]142
[e2ab36f1]143 /** Incoming client task ID. */
144 task_id_t in_task_id;
[a35b458]145
[23882034]146 /** Link to the client tracking structure. */
147 client_t *client;
[a35b458]148
[1de92fb0]149 /** Channel for messages that should be delivered to this fibril. */
150 mpsc_t *msg_channel;
[a35b458]151
[e70bfa5]152 /** Call data of the opening call. */
[80649a91]153 ipc_call_t call;
[a35b458]154
[e70bfa5]155 /** Fibril function that will be used to handle the connection. */
[b688fd8]156 async_port_handler_t handler;
[a35b458]157
[b688fd8]158 /** Client data */
159 void *data;
[80649a91]160} connection_t;
161
[8dab988]162/* Member of notification_t::msg_list. */
163typedef struct {
164 link_t link;
165 ipc_call_t calldata;
166} notification_msg_t;
167
[8820544]168/* Notification data */
169typedef struct {
[3b1cc8d]170 /** notification_hash_table link */
171 ht_link_t htlink;
172
173 /** notification_queue link */
174 link_t qlink;
[a35b458]175
[8820544]176 /** Notification method */
177 sysarg_t imethod;
[a35b458]178
[8820544]179 /** Notification handler */
180 async_notification_handler_t handler;
[a35b458]181
[3b1cc8d]182 /** Notification handler argument */
183 void *arg;
184
[8dab988]185 /** List of arrived notifications. */
186 list_t msg_list;
[8820544]187} notification_t;
188
[bc1f1c2]189/** Identifier of the incoming connection handled by the current fibril. */
[79ae36dd]190static fibril_local connection_t *fibril_connection;
[e70bfa5]191
[46eec3b]192static void *default_client_data_constructor(void)
193{
194 return NULL;
195}
196
197static void default_client_data_destructor(void *data)
198{
199}
200
201static async_client_data_ctor_t async_client_data_create =
202 default_client_data_constructor;
203static async_client_data_dtor_t async_client_data_destroy =
204 default_client_data_destructor;
205
206void async_set_client_data_constructor(async_client_data_ctor_t ctor)
207{
[f302586]208 assert(async_client_data_create == default_client_data_constructor);
[46eec3b]209 async_client_data_create = ctor;
210}
211
212void async_set_client_data_destructor(async_client_data_dtor_t dtor)
213{
[f302586]214 assert(async_client_data_destroy == default_client_data_destructor);
[46eec3b]215 async_client_data_destroy = dtor;
216}
217
[0a8f070]218static async_client_conn_t implicit_connection = NULL;
[45c8eea]219static fibril_rmutex_t client_mutex;
[c80fdd0]220static hash_table_t client_hash_table;
[3b1cc8d]221
222// TODO: lockfree notification_queue?
[45c8eea]223static fibril_rmutex_t notification_mutex;
[8820544]224static hash_table_t notification_hash_table;
[3b1cc8d]225static LIST_INITIALIZE(notification_queue);
226static FIBRIL_SEMAPHORE_INITIALIZE(notification_semaphore, 0);
227
[8dab988]228static LIST_INITIALIZE(notification_freelist);
229static long notification_freelist_total = 0;
230static long notification_freelist_used = 0;
231
[8820544]232static sysarg_t notification_avail = 0;
233
[5e801dc]234static size_t client_key_hash(const void *key)
[c80fdd0]235{
[5e801dc]236 const task_id_t *in_task_id = key;
237 return *in_task_id;
[c80fdd0]238}
239
[062d900]240static size_t client_hash(const ht_link_t *item)
[c80fdd0]241{
[062d900]242 client_t *client = hash_table_get_inst(item, client_t, link);
243 return client_key_hash(&client->in_task_id);
[c80fdd0]244}
245
[5e801dc]246static bool client_key_equal(const void *key, const ht_link_t *item)
[c80fdd0]247{
[5e801dc]248 const task_id_t *in_task_id = key;
[062d900]249 client_t *client = hash_table_get_inst(item, client_t, link);
[5e801dc]250 return *in_task_id == client->in_task_id;
[c80fdd0]251}
252
253/** Operations for the client hash table. */
[062d900]254static hash_table_ops_t client_hash_table_ops = {
[c80fdd0]255 .hash = client_hash,
[062d900]256 .key_hash = client_key_hash,
257 .key_equal = client_key_equal,
[4e00f87]258 .equal = NULL,
259 .remove_callback = NULL
[c80fdd0]260};
[80649a91]261
[9ef495f]262static client_t *async_client_get(task_id_t client_id, bool create)
263{
264 client_t *client = NULL;
[a35b458]265
[9bde0d5]266 fibril_rmutex_lock(&client_mutex);
[9ef495f]267 ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
268 if (link) {
269 client = hash_table_get_inst(link, client_t, link);
[498ced1]270 client->refcnt++;
[9ef495f]271 } else if (create) {
[3bd1d7d4]272 // TODO: move the malloc out of critical section
[9bde0d5]273 /* malloc() is rmutex safe. */
[9ef495f]274 client = malloc(sizeof(client_t));
275 if (client) {
276 client->in_task_id = client_id;
277 client->data = async_client_data_create();
[a35b458]278
[498ced1]279 client->refcnt = 1;
[9ef495f]280 hash_table_insert(&client_hash_table, &client->link);
281 }
282 }
[a35b458]283
[9bde0d5]284 fibril_rmutex_unlock(&client_mutex);
[9ef495f]285 return client;
286}
287
288static void async_client_put(client_t *client)
289{
290 bool destroy;
[a35b458]291
[9bde0d5]292 fibril_rmutex_lock(&client_mutex);
[a35b458]293
[498ced1]294 if (--client->refcnt == 0) {
[9ef495f]295 hash_table_remove(&client_hash_table, &client->in_task_id);
296 destroy = true;
297 } else
298 destroy = false;
[a35b458]299
[9bde0d5]300 fibril_rmutex_unlock(&client_mutex);
[a35b458]301
[9ef495f]302 if (destroy) {
303 if (client->data)
304 async_client_data_destroy(client->data);
[a35b458]305
[9ef495f]306 free(client);
307 }
308}
309
310/** Wrapper for client connection fibril.
311 *
312 * When a new connection arrives, a fibril with this implementing
313 * function is created.
314 *
315 * @param arg Connection structure pointer.
316 *
317 * @return Always zero.
318 *
319 */
[b7fd2a0]320static errno_t connection_fibril(void *arg)
[9ef495f]321{
322 assert(arg);
[a35b458]323
[9ef495f]324 /*
325 * Setup fibril-local connection pointer.
326 */
327 fibril_connection = (connection_t *) arg;
[a35b458]328
[6769005]329 mpsc_t *c = fibril_connection->msg_channel;
330
[9ef495f]331 /*
332 * Add our reference for the current connection in the client task
333 * tracking structure. If this is the first reference, create and
334 * hash in a new tracking structure.
335 */
[a35b458]336
[9ef495f]337 client_t *client = async_client_get(fibril_connection->in_task_id, true);
338 if (!client) {
[061274f]339 ipc_answer_0(fibril_connection->call.cap_handle, ENOMEM);
[6769005]340 goto out;
[9ef495f]341 }
[a35b458]342
[9ef495f]343 fibril_connection->client = client;
[a35b458]344
[9ef495f]345 /*
346 * Call the connection handler function.
347 */
[984a9ba]348 fibril_connection->handler(&fibril_connection->call,
349 fibril_connection->data);
[a35b458]350
[9ef495f]351 /*
352 * Remove the reference for this client task connection.
353 */
354 async_client_put(client);
[a35b458]355
[1de92fb0]356 /*
357 * Close the channel, if it isn't closed already.
358 */
359 mpsc_close(c);
360
[9ef495f]361 /*
362 * Answer all remaining messages with EHANGUP.
363 */
[1de92fb0]364 ipc_call_t call;
365 while (mpsc_receive(c, &call, NULL) == EOK)
366 ipc_answer_0(call.cap_handle, EHANGUP);
[a35b458]367
[9ef495f]368 /*
[1de92fb0]369 * Clean up memory.
[9ef495f]370 */
[6769005]371out:
[1de92fb0]372 mpsc_destroy(c);
[9ef495f]373 free(fibril_connection);
[d5c1051]374 return EOK;
[9ef495f]375}
376
[6769005]377/** Return label usable during replies to IPC_M_CONNECT_ME_TO. */
378sysarg_t async_get_label(void)
379{
[53ee7a0]380 return (sysarg_t) fibril_connection;
[6769005]381}
382
[9ef495f]383/** Create a new fibril for a new connection.
384 *
[01c3bb4]385 * Create new fibril for connection, fill in connection structures and insert it
386 * into the hash table, so that later we can easily do routing of messages to
387 * particular fibrils.
[9ef495f]388 *
[6769005]389 * @param conn Pointer to the connection structure. Will be used as the
390 * label of the connected phone and request_label of incoming
391 * calls routed through that phone.
392 * @param in_task_id Identification of the incoming connection.
393 * @param call Call data of the opening call. If call is NULL, the
394 * connection was opened by accepting the
395 * IPC_M_CONNECT_TO_ME call and this function is called
396 * directly by the server.
397 * @param handler Connection handler.
398 * @param data Client argument to pass to the connection handler.
[9ef495f]399 *
[01c3bb4]400 * @return New fibril id or NULL on failure.
[9ef495f]401 *
402 */
[6769005]403static fid_t async_new_connection(connection_t *conn, task_id_t in_task_id,
[061274f]404 ipc_call_t *call, async_port_handler_t handler, void *data)
[9ef495f]405{
406 conn->in_task_id = in_task_id;
[1de92fb0]407 conn->msg_channel = mpsc_create(sizeof(ipc_call_t));
[9ef495f]408 conn->handler = handler;
409 conn->data = data;
[a35b458]410
[6769005]411 if (!conn->msg_channel)
412 goto error;
413
[9ef495f]414 if (call)
415 conn->call = *call;
[061274f]416 else
417 conn->call.cap_handle = CAP_NIL;
[a35b458]418
[9ef495f]419 /* We will activate the fibril ASAP */
[514d561]420 conn->fid = fibril_create(connection_fibril, conn);
[a35b458]421
[6769005]422 if (conn->fid == 0)
423 goto error;
[a35b458]424
[6769005]425 fibril_start(conn->fid);
[a35b458]426
[6769005]427 return conn->fid;
[a35b458]428
[6769005]429error:
430 if (conn->msg_channel)
431 mpsc_destroy(conn->msg_channel);
432 free(conn);
[a35b458]433
[6769005]434 if (call)
435 ipc_answer_0(call->cap_handle, ENOMEM);
[a35b458]436
[6769005]437 return (fid_t) NULL;
[9ef495f]438}
439
[78bb04b]440/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
441 *
442 * Ask through phone for a new connection to some service.
443 *
444 * @param exch Exchange for sending the message.
445 * @param iface Callback interface.
446 * @param arg1 User defined argument.
447 * @param arg2 User defined argument.
448 * @param handler Callback handler.
449 * @param data Handler data.
450 * @param port_id ID of the newly created port.
451 *
[cde999a]452 * @return Zero on success or an error code.
[78bb04b]453 *
454 */
[b7fd2a0]455errno_t async_create_callback_port(async_exch_t *exch, iface_t iface, sysarg_t arg1,
[78bb04b]456 sysarg_t arg2, async_port_handler_t handler, void *data, port_id_t *port_id)
457{
458 if ((iface & IFACE_MOD_CALLBACK) != IFACE_MOD_CALLBACK)
459 return EINVAL;
[a35b458]460
[78bb04b]461 if (exch == NULL)
462 return ENOENT;
[a35b458]463
[6769005]464 connection_t *conn = calloc(1, sizeof(*conn));
465 if (!conn)
466 return ENOMEM;
467
[78bb04b]468 ipc_call_t answer;
[6769005]469 aid_t req = async_send_5(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2,
470 0, (sysarg_t) conn, &answer);
[a35b458]471
[fda19b8]472 errno_t rc;
473 async_wait_for(req, &rc);
[6769005]474 if (rc != EOK) {
475 free(conn);
[fda19b8]476 return rc;
[6769005]477 }
[a35b458]478
[fda19b8]479 rc = async_create_port_internal(iface, handler, data, port_id);
[6769005]480 if (rc != EOK) {
481 free(conn);
[fda19b8]482 return rc;
[6769005]483 }
[a35b458]484
[6769005]485 fid_t fid = async_new_connection(conn, answer.task_id, NULL, handler,
486 data);
[514d561]487 if (fid == (fid_t) NULL)
[78bb04b]488 return ENOMEM;
[a35b458]489
[78bb04b]490 return EOK;
491}
492
[5e801dc]493static size_t notification_key_hash(const void *key)
[8820544]494{
[5e801dc]495 const sysarg_t *id = key;
496 return *id;
[8820544]497}
498
499static size_t notification_hash(const ht_link_t *item)
500{
501 notification_t *notification =
[3b1cc8d]502 hash_table_get_inst(item, notification_t, htlink);
[8820544]503 return notification_key_hash(&notification->imethod);
504}
505
[5e801dc]506static bool notification_key_equal(const void *key, const ht_link_t *item)
[8820544]507{
[5e801dc]508 const sysarg_t *id = key;
[8820544]509 notification_t *notification =
[3b1cc8d]510 hash_table_get_inst(item, notification_t, htlink);
[5e801dc]511 return *id == notification->imethod;
[8820544]512}
513
514/** Operations for the notification hash table. */
515static hash_table_ops_t notification_hash_table_ops = {
516 .hash = notification_hash,
517 .key_hash = notification_key_hash,
518 .key_equal = notification_key_equal,
519 .equal = NULL,
520 .remove_callback = NULL
521};
522
[e70bfa5]523/** Try to route a call to an appropriate connection fibril.
[80649a91]524 *
[36c9234]525 * If the proper connection fibril is found, a message with the call is added to
526 * its message queue. If the fibril was not active, it is activated and all
527 * timeouts are unregistered.
528 *
[061274f]529 * @param call Data of the incoming call.
[c07544d3]530 *
[1de92fb0]531 * @return EOK if the call was successfully passed to the respective fibril.
532 * @return ENOENT if the call doesn't match any connection.
533 * @return Other error code if routing failed for other reasons.
[36c9234]534 *
[80649a91]535 */
[1de92fb0]536static errno_t route_call(ipc_call_t *call)
[450cd3a]537{
[79ae36dd]538 assert(call);
[a35b458]539
[6769005]540 connection_t *conn = (connection_t *) call->request_label;
[a35b458]541
[6769005]542 if (!conn)
[1de92fb0]543 return ENOENT;
[a35b458]544
[6769005]545 assert(conn->msg_channel);
[a35b458]546
[1de92fb0]547 errno_t rc = mpsc_send(conn->msg_channel, call);
[a35b458]548
[fafb8e5]549 if (ipc_get_imethod(call) == IPC_M_PHONE_HUNGUP) {
[1de92fb0]550 /* Close the channel, but let the connection fibril answer. */
551 mpsc_close(conn->msg_channel);
552 // FIXME: Ideally, we should be able to discard/answer the
553 // hungup message here and just close the channel without
554 // passing it out. Unfortunatelly, somehow that breaks
555 // handling of CPU exceptions.
556 }
[a35b458]557
[1de92fb0]558 return rc;
[c07544d3]559}
[80649a91]560
[3b1cc8d]561/** Function implementing the notification handler fibril. Never returns. */
562static errno_t notification_fibril_func(void *arg)
563{
564 (void) arg;
565
566 while (true) {
567 fibril_semaphore_down(&notification_semaphore);
568
[9bde0d5]569 fibril_rmutex_lock(&notification_mutex);
[3b1cc8d]570
571 /*
572 * The semaphore ensures that if we get this far,
573 * the queue must be non-empty.
574 */
575 assert(!list_empty(&notification_queue));
576
577 notification_t *notification = list_get_instance(
578 list_first(&notification_queue), notification_t, qlink);
579
580 async_notification_handler_t handler = notification->handler;
581 void *arg = notification->arg;
582
[8dab988]583 notification_msg_t *m = list_pop(&notification->msg_list,
584 notification_msg_t, link);
585 assert(m);
586 ipc_call_t calldata = m->calldata;
587
588 notification_freelist_used--;
589
590 if (notification_freelist_total > 64 &&
591 notification_freelist_total > 2 * notification_freelist_used) {
592 /* Going to free the structure if we have too much. */
593 notification_freelist_total--;
594 } else {
595 /* Otherwise add to freelist. */
596 list_append(&m->link, &notification_freelist);
597 m = NULL;
598 }
[3b1cc8d]599
[8dab988]600 if (list_empty(&notification->msg_list))
601 list_remove(&notification->qlink);
[3b1cc8d]602
[9bde0d5]603 fibril_rmutex_unlock(&notification_mutex);
[3b1cc8d]604
605 if (handler)
606 handler(&calldata, arg);
[8dab988]607
608 free(m);
[3b1cc8d]609 }
610
611 /* Not reached. */
612 return EOK;
613}
614
615/**
616 * Creates a new dedicated fibril for handling notifications.
617 * By default, there is one such fibril. This function can be used to
618 * create more in order to increase the number of notification that can
619 * be processed concurrently.
620 *
621 * Currently, there is no way to destroy those fibrils after they are created.
622 */
623errno_t async_spawn_notification_handler(void)
624{
625 fid_t f = fibril_create(notification_fibril_func, NULL);
626 if (f == 0)
627 return ENOMEM;
628
629 fibril_add_ready(f);
630 return EOK;
631}
632
633/** Queue notification.
[c07544d3]634 *
[c170438]635 * @param call Data of the incoming call.
[58563585]636 *
[c07544d3]637 */
[3b1cc8d]638static void queue_notification(ipc_call_t *call)
[c07544d3]639{
[c170438]640 assert(call);
[a35b458]641
[9bde0d5]642 fibril_rmutex_lock(&notification_mutex);
[a35b458]643
[8dab988]644 notification_msg_t *m = list_pop(&notification_freelist,
645 notification_msg_t, link);
646
647 if (!m) {
[9bde0d5]648 fibril_rmutex_unlock(&notification_mutex);
[8dab988]649 m = malloc(sizeof(notification_msg_t));
650 if (!m) {
651 DPRINTF("Out of memory.\n");
652 abort();
653 }
654
[9bde0d5]655 fibril_rmutex_lock(&notification_mutex);
[8dab988]656 notification_freelist_total++;
657 }
658
[95a47b0]659 sysarg_t imethod = ipc_get_imethod(call);
660 ht_link_t *link = hash_table_find(&notification_hash_table, &imethod);
[3b1cc8d]661 if (!link) {
662 /* Invalid notification. */
663 // TODO: Make sure this can't happen and turn it into assert.
[8dab988]664 notification_freelist_total--;
[9bde0d5]665 fibril_rmutex_unlock(&notification_mutex);
[8dab988]666 free(m);
[3b1cc8d]667 return;
[8820544]668 }
[a35b458]669
[3b1cc8d]670 notification_t *notification =
671 hash_table_get_inst(link, notification_t, htlink);
672
[8dab988]673 notification_freelist_used++;
674 m->calldata = *call;
675 list_append(&m->link, &notification->msg_list);
[3b1cc8d]676
[8dab988]677 if (!link_in_use(&notification->qlink))
678 list_append(&notification->qlink, &notification_queue);
[3b1cc8d]679
[9bde0d5]680 fibril_rmutex_unlock(&notification_mutex);
[3b1cc8d]681
682 fibril_semaphore_up(&notification_semaphore);
683}
684
685/**
686 * Creates a new notification structure and inserts it into the hash table.
687 *
688 * @param handler Function to call when notification is received.
689 * @param arg Argument for the handler function.
690 * @return The newly created notification structure.
691 */
692static notification_t *notification_create(async_notification_handler_t handler, void *arg)
693{
694 notification_t *notification = calloc(1, sizeof(notification_t));
695 if (!notification)
696 return NULL;
697
698 notification->handler = handler;
699 notification->arg = arg;
700
[8dab988]701 list_initialize(&notification->msg_list);
702
[3b1cc8d]703 fid_t fib = 0;
704
[9bde0d5]705 fibril_rmutex_lock(&notification_mutex);
[3b1cc8d]706
707 if (notification_avail == 0) {
708 /* Attempt to create the first handler fibril. */
709 fib = fibril_create(notification_fibril_func, NULL);
710 if (fib == 0) {
[9bde0d5]711 fibril_rmutex_unlock(&notification_mutex);
[3b1cc8d]712 free(notification);
713 return NULL;
714 }
715 }
716
717 sysarg_t imethod = notification_avail;
718 notification_avail++;
719
720 notification->imethod = imethod;
721 hash_table_insert(&notification_hash_table, &notification->htlink);
722
[9bde0d5]723 fibril_rmutex_unlock(&notification_mutex);
[3b1cc8d]724
725 if (imethod == 0) {
726 assert(fib);
727 fibril_add_ready(fib);
728 }
[a35b458]729
[3b1cc8d]730 return notification;
[80649a91]731}
732
[8820544]733/** Subscribe to IRQ notification.
734 *
735 * @param inr IRQ number.
736 * @param handler Notification handler.
737 * @param data Notification handler client data.
738 * @param ucode Top-half pseudocode handler.
739 *
[071a1ddb]740 * @param[out] handle IRQ capability handle on success.
741 *
[cde999a]742 * @return An error code.
[8820544]743 *
744 */
[b7fd2a0]745errno_t async_irq_subscribe(int inr, async_notification_handler_t handler,
[eadaeae8]746 void *data, const irq_code_t *ucode, cap_irq_handle_t *handle)
[8820544]747{
[3b1cc8d]748 notification_t *notification = notification_create(handler, data);
[8820544]749 if (!notification)
750 return ENOMEM;
[a35b458]751
[eadaeae8]752 cap_irq_handle_t ihandle;
[3b1cc8d]753 errno_t rc = ipc_irq_subscribe(inr, notification->imethod, ucode,
754 &ihandle);
[071a1ddb]755 if (rc == EOK && handle != NULL) {
[eadaeae8]756 *handle = ihandle;
[9233e9d]757 }
[071a1ddb]758 return rc;
[8820544]759}
760
761/** Unsubscribe from IRQ notification.
762 *
[eadaeae8]763 * @param handle IRQ capability handle.
[8820544]764 *
[cde999a]765 * @return Zero on success or an error code.
[8820544]766 *
767 */
[eadaeae8]768errno_t async_irq_unsubscribe(cap_irq_handle_t ihandle)
[8820544]769{
770 // TODO: Remove entry from hash table
771 // to avoid memory leak
[a35b458]772
[eadaeae8]773 return ipc_irq_unsubscribe(ihandle);
[8820544]774}
775
776/** Subscribe to event notifications.
777 *
778 * @param evno Event type to subscribe.
779 * @param handler Notification handler.
780 * @param data Notification handler client data.
781 *
[cde999a]782 * @return Zero on success or an error code.
[8820544]783 *
784 */
[b7fd2a0]785errno_t async_event_subscribe(event_type_t evno,
[8820544]786 async_notification_handler_t handler, void *data)
787{
[3b1cc8d]788 notification_t *notification = notification_create(handler, data);
[8820544]789 if (!notification)
790 return ENOMEM;
[a35b458]791
[3b1cc8d]792 return ipc_event_subscribe(evno, notification->imethod);
[8820544]793}
794
795/** Subscribe to task event notifications.
796 *
797 * @param evno Event type to subscribe.
798 * @param handler Notification handler.
799 * @param data Notification handler client data.
800 *
[cde999a]801 * @return Zero on success or an error code.
[8820544]802 *
803 */
[b7fd2a0]804errno_t async_event_task_subscribe(event_task_type_t evno,
[8820544]805 async_notification_handler_t handler, void *data)
806{
[3b1cc8d]807 notification_t *notification = notification_create(handler, data);
[8820544]808 if (!notification)
809 return ENOMEM;
[a35b458]810
[3b1cc8d]811 return ipc_event_task_subscribe(evno, notification->imethod);
[8820544]812}
813
814/** Unmask event notifications.
815 *
816 * @param evno Event type to unmask.
817 *
818 * @return Value returned by the kernel.
819 *
820 */
[b7fd2a0]821errno_t async_event_unmask(event_type_t evno)
[8820544]822{
823 return ipc_event_unmask(evno);
824}
825
826/** Unmask task event notifications.
827 *
828 * @param evno Event type to unmask.
829 *
830 * @return Value returned by the kernel.
831 *
832 */
[b7fd2a0]833errno_t async_event_task_unmask(event_task_type_t evno)
[8820544]834{
835 return ipc_event_task_unmask(evno);
836}
837
[e70bfa5]838/** Return new incoming message for the current (fibril-local) connection.
839 *
[984a9ba]840 * @param call Storage where the incoming call data will be stored.
841 * @param usecs Timeout in microseconds. Zero denotes no timeout.
842 *
843 * @return If no timeout was specified, then true is returned.
844 * @return If a timeout is specified, then true is returned unless
845 * the timeout expires prior to receiving a message.
[e70bfa5]846 *
847 */
[bd41ac52]848bool async_get_call_timeout(ipc_call_t *call, usec_t usecs)
[80649a91]849{
[79ae36dd]850 assert(call);
851 assert(fibril_connection);
[a35b458]852
[bd41ac52]853 struct timespec ts;
854 struct timespec *expires = NULL;
[49d072e]855 if (usecs) {
[bd41ac52]856 getuptime(&ts);
857 ts_add_diff(&ts, USEC2NSEC(usecs));
858 expires = &ts;
[514d561]859 }
860
[1de92fb0]861 errno_t rc = mpsc_receive(fibril_connection->msg_channel,
862 call, expires);
[a35b458]863
[1de92fb0]864 if (rc == ETIMEOUT)
865 return false;
[a35b458]866
[1de92fb0]867 if (rc != EOK) {
868 /*
869 * The async_get_call_timeout() interface doesn't support
870 * propagating errors. Return a null call instead.
871 */
[514d561]872
[1de92fb0]873 memset(call, 0, sizeof(ipc_call_t));
[fafb8e5]874 ipc_set_imethod(call, IPC_M_PHONE_HUNGUP);
[de9a18e]875 call->cap_handle = CAP_NIL;
[450cd3a]876 }
[a35b458]877
[984a9ba]878 return true;
[80649a91]879}
880
[4f13e19]881bool async_get_call(ipc_call_t *call)
882{
883 return async_get_call_timeout(call, 0);
884}
885
[455f190]886void *async_get_client_data(void)
887{
888 assert(fibril_connection);
889 return fibril_connection->client->data;
890}
891
[e2ab36f1]892void *async_get_client_data_by_id(task_id_t client_id)
[455f190]893{
[e2ab36f1]894 client_t *client = async_client_get(client_id, false);
[455f190]895 if (!client)
896 return NULL;
[a35b458]897
[455f190]898 if (!client->data) {
899 async_client_put(client);
900 return NULL;
901 }
[a35b458]902
[455f190]903 return client->data;
904}
905
[e2ab36f1]906void async_put_client_data_by_id(task_id_t client_id)
[455f190]907{
[e2ab36f1]908 client_t *client = async_client_get(client_id, false);
[a35b458]909
[455f190]910 assert(client);
911 assert(client->data);
[a35b458]912
[cdc8ee2d]913 /* Drop the reference we got in async_get_client_data_by_hash(). */
914 async_client_put(client);
[a35b458]915
[cdc8ee2d]916 /* Drop our own reference we got at the beginning of this function. */
[455f190]917 async_client_put(client);
918}
919
[36c9234]920/** Handle a call that was received.
921 *
922 * If the call has the IPC_M_CONNECT_ME_TO method, a new connection is created.
923 * Otherwise the call is routed to its connection fibril.
924 *
[061274f]925 * @param call Data of the incoming call.
[6b21292]926 *
[36c9234]927 */
[061274f]928static void handle_call(ipc_call_t *call)
[80649a91]929{
[79ae36dd]930 assert(call);
[a35b458]931
[d054ad3]932 if (call->flags & IPC_CALL_ANSWERED) {
933 /* Answer to a call made by us. */
934 async_reply_received(call);
[e768aea]935 return;
[d054ad3]936 }
[e768aea]937
[061274f]938 if (call->cap_handle == CAP_NIL) {
[e768aea]939 if (call->flags & IPC_CALL_NOTIF) {
940 /* Kernel notification */
941 queue_notification(call);
942 }
[47b7006]943 return;
[6b21292]944 }
[a35b458]945
[566992e1]946 /* New connection */
[fafb8e5]947 if (ipc_get_imethod(call) == IPC_M_CONNECT_ME_TO) {
[6769005]948 connection_t *conn = calloc(1, sizeof(*conn));
949 if (!conn) {
950 ipc_answer_0(call->cap_handle, ENOMEM);
951 return;
952 }
953
[fafb8e5]954 iface_t iface = (iface_t) ipc_get_arg1(call);
[a35b458]955
[49a796f1]956 // TODO: Currently ignores all ports but the first one.
957 void *data;
958 async_port_handler_t handler =
959 async_get_port_handler(iface, 0, &data);
[a35b458]960
[6769005]961 async_new_connection(conn, call->task_id, call, handler, data);
[566992e1]962 return;
963 }
[a35b458]964
[6769005]965 /* Route the call according to its request label */
[1de92fb0]966 errno_t rc = route_call(call);
[0a8f070]967 if (rc == EOK) {
[47b7006]968 return;
[0a8f070]969 } else if (implicit_connection != NULL) {
970 async_new_connection(call->in_task_id, call->in_phone_hash,
971 callid, call, implicit_connection, NULL);
972 return;
973 }
[a35b458]974
[1de92fb0]975 // TODO: Log the error.
976
977 if (call->cap_handle != CAP_NIL)
978 /* Unknown call from unknown phone - hang it up */
979 ipc_answer_0(call->cap_handle, EHANGUP);
[450cd3a]980}
981
[36c9234]982/** Endless loop dispatching incoming calls and answers.
983 *
[c07544d3]984 * @return Never returns.
985 *
[36c9234]986 */
[b7fd2a0]987static errno_t async_manager_worker(void)
[80649a91]988{
[514d561]989 ipc_call_t call;
990 errno_t rc;
[a35b458]991
[514d561]992 while (true) {
993 rc = fibril_ipc_wait(&call, NULL);
[acf6b55]994 if (rc == EOK)
995 handle_call(&call);
[80649a91]996 }
[01c3bb4]997
[a46da63]998 return 0;
[80649a91]999}
1000
[36c9234]1001/** Function to start async_manager as a standalone fibril.
[c07544d3]1002 *
[36c9234]1003 * When more kernel threads are used, one async manager should exist per thread.
1004 *
[c07544d3]1005 * @param arg Unused.
1006 * @return Never returns.
[36c9234]1007 *
[a2cd194]1008 */
[b7fd2a0]1009static errno_t async_manager_fibril(void *arg)
[80649a91]1010{
[085bd54]1011 async_manager_worker();
[a46da63]1012 return 0;
[80649a91]1013}
[450cd3a]1014
[36c9234]1015/** Add one manager to manager list. */
[fec7ba0]1016static fid_t async_create_manager(void)
[450cd3a]1017{
[c170438]1018 fid_t fid = fibril_create_generic(async_manager_fibril, NULL, PAGE_SIZE);
[514d561]1019 fibril_start(fid);
1020 return fid;
[80649a91]1021}
1022
[36c9234]1023/** Initialize the async framework.
1024 *
1025 */
[49a796f1]1026void __async_server_init(void)
[80649a91]1027{
[45c8eea]1028 if (fibril_rmutex_initialize(&client_mutex) != EOK)
1029 abort();
1030 if (fibril_rmutex_initialize(&notification_mutex) != EOK)
1031 abort();
1032
[062d900]1033 if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
[47b7006]1034 abort();
[a35b458]1035
[8820544]1036 if (!hash_table_create(&notification_hash_table, 0, 0,
1037 &notification_hash_table_ops))
1038 abort();
[514d561]1039
1040 async_create_manager();
[49a796f1]1041}
[a35b458]1042
[25f6bddb]1043void __async_server_fini(void)
1044{
1045 fibril_rmutex_destroy(&client_mutex);
1046 fibril_rmutex_destroy(&notification_mutex);
1047}
1048
[beb83c1]1049errno_t async_accept_0(ipc_call_t *call)
1050{
[d57c7c2]1051 cap_call_handle_t chandle = call->cap_handle;
1052 assert(chandle != CAP_NIL);
1053 call->cap_handle = CAP_NIL;
1054 return ipc_answer_5(chandle, EOK, 0, 0, 0, 0, async_get_label());
[beb83c1]1055}
1056
[984a9ba]1057errno_t async_answer_0(ipc_call_t *call, errno_t retval)
[49a796f1]1058{
[d57c7c2]1059 cap_call_handle_t chandle = call->cap_handle;
1060 assert(chandle != CAP_NIL);
1061 call->cap_handle = CAP_NIL;
1062 return ipc_answer_0(chandle, retval);
[450cd3a]1063}
[01ff41c]1064
[984a9ba]1065errno_t async_answer_1(ipc_call_t *call, errno_t retval, sysarg_t arg1)
[01ff41c]1066{
[d57c7c2]1067 cap_call_handle_t chandle = call->cap_handle;
1068 assert(chandle != CAP_NIL);
1069 call->cap_handle = CAP_NIL;
1070 return ipc_answer_1(chandle, retval, arg1);
[49a796f1]1071}
[a35b458]1072
[984a9ba]1073errno_t async_answer_2(ipc_call_t *call, errno_t retval, sysarg_t arg1,
[49a796f1]1074 sysarg_t arg2)
1075{
[d57c7c2]1076 cap_call_handle_t chandle = call->cap_handle;
1077 assert(chandle != CAP_NIL);
1078 call->cap_handle = CAP_NIL;
1079 return ipc_answer_2(chandle, retval, arg1, arg2);
[49a796f1]1080}
[a35b458]1081
[984a9ba]1082errno_t async_answer_3(ipc_call_t *call, errno_t retval, sysarg_t arg1,
[49a796f1]1083 sysarg_t arg2, sysarg_t arg3)
1084{
[d57c7c2]1085 cap_call_handle_t chandle = call->cap_handle;
1086 assert(chandle != CAP_NIL);
1087 call->cap_handle = CAP_NIL;
1088 return ipc_answer_3(chandle, retval, arg1, arg2, arg3);
[49a796f1]1089}
[a35b458]1090
[984a9ba]1091errno_t async_answer_4(ipc_call_t *call, errno_t retval, sysarg_t arg1,
[49a796f1]1092 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
1093{
[d57c7c2]1094 cap_call_handle_t chandle = call->cap_handle;
1095 assert(chandle != CAP_NIL);
1096 call->cap_handle = CAP_NIL;
1097 return ipc_answer_4(chandle, retval, arg1, arg2, arg3, arg4);
[49a796f1]1098}
[a35b458]1099
[984a9ba]1100errno_t async_answer_5(ipc_call_t *call, errno_t retval, sysarg_t arg1,
[49a796f1]1101 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
1102{
[d57c7c2]1103 cap_call_handle_t chandle = call->cap_handle;
1104 assert(chandle != CAP_NIL);
1105 call->cap_handle = CAP_NIL;
1106 return ipc_answer_5(chandle, retval, arg1, arg2, arg3, arg4, arg5);
[49a796f1]1107}
[a35b458]1108
[4f13e19]1109static errno_t async_forward_fast(ipc_call_t *call, async_exch_t *exch,
[49a796f1]1110 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
1111{
[984a9ba]1112 assert(call);
1113
[d57c7c2]1114 cap_call_handle_t chandle = call->cap_handle;
1115 assert(chandle != CAP_NIL);
1116 call->cap_handle = CAP_NIL;
1117
[49a796f1]1118 if (exch == NULL)
1119 return ENOENT;
[a35b458]1120
[d57c7c2]1121 return ipc_forward_fast(chandle, exch->phone, imethod, arg1, arg2,
1122 mode);
[49a796f1]1123}
[a35b458]1124
[4f13e19]1125static errno_t async_forward_slow(ipc_call_t *call, async_exch_t *exch,
[49a796f1]1126 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
1127 sysarg_t arg4, sysarg_t arg5, unsigned int mode)
1128{
[984a9ba]1129 assert(call);
1130
[d57c7c2]1131 cap_call_handle_t chandle = call->cap_handle;
1132 assert(chandle != CAP_NIL);
1133 call->cap_handle = CAP_NIL;
1134
[49a796f1]1135 if (exch == NULL)
1136 return ENOENT;
[a35b458]1137
[d57c7c2]1138 return ipc_forward_slow(chandle, exch->phone, imethod, arg1, arg2, arg3,
1139 arg4, arg5, mode);
[01ff41c]1140}
1141
[4f13e19]1142errno_t async_forward_0(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1143 unsigned int mode)
1144{
1145 return async_forward_fast(call, exch, imethod, 0, 0, mode);
1146}
1147
1148errno_t async_forward_1(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1149 sysarg_t arg1, unsigned int mode)
1150{
1151 return async_forward_fast(call, exch, imethod, arg1, 0, mode);
1152}
1153
1154errno_t async_forward_2(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1155 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
1156{
1157 return async_forward_fast(call, exch, imethod, arg1, arg2, mode);
1158}
1159
1160errno_t async_forward_3(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1161 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, unsigned int mode)
1162{
1163 return async_forward_slow(call, exch, imethod, arg1, arg2, arg3, 0, 0,
1164 mode);
1165}
1166
1167errno_t async_forward_4(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1168 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
1169 unsigned int mode)
1170{
1171 return async_forward_slow(call, exch, imethod, arg1, arg2, arg3, arg4,
1172 0, mode);
1173}
1174
1175errno_t async_forward_5(ipc_call_t *call, async_exch_t *exch, sysarg_t imethod,
1176 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
1177 unsigned int mode)
1178{
1179 return async_forward_slow(call, exch, imethod, arg1, arg2, arg3, arg4,
1180 arg5, mode);
1181}
1182
[49a796f1]1183/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
[36c9234]1184 *
[49a796f1]1185 * Ask through phone for a new connection to some service.
[01ff41c]1186 *
[9b1baac]1187 * @param exch Exchange for sending the message.
1188 * @param iface Callback interface.
1189 * @param arg2 User defined argument.
1190 * @param arg3 User defined argument.
[c07544d3]1191 *
[49a796f1]1192 * @return Zero on success or an error code.
[36c9234]1193 *
[01ff41c]1194 */
[9b1baac]1195errno_t async_connect_to_me(async_exch_t *exch, iface_t iface, sysarg_t arg2,
[49a796f1]1196 sysarg_t arg3)
[01ff41c]1197{
[79ae36dd]1198 if (exch == NULL)
[49a796f1]1199 return ENOENT;
[a35b458]1200
[6769005]1201 sysarg_t label = 0;
1202 errno_t rc = async_req_5_0(exch, IPC_M_CONNECT_TO_ME, iface, arg2, arg3,
1203 0, label);
[a35b458]1204
[6769005]1205 return rc;
[49a796f1]1206}
[a35b458]1207
[49a796f1]1208/** Wrapper for receiving the IPC_M_SHARE_IN calls using the async framework.
[0da4e41]1209 *
[47b7006]1210 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_IN
1211 * calls so that the user doesn't have to remember the meaning of each IPC
1212 * argument.
[0da4e41]1213 *
1214 * So far, this wrapper is to be used from within a connection fibril.
1215 *
[984a9ba]1216 * @param call Storage for the data of the IPC_M_SHARE_IN call.
1217 * @param size Destination address space area size.
[47b7006]1218 *
1219 * @return True on success, false on failure.
[0da4e41]1220 *
1221 */
[984a9ba]1222bool async_share_in_receive(ipc_call_t *call, size_t *size)
[0da4e41]1223{
[984a9ba]1224 assert(call);
[0da4e41]1225 assert(size);
[a35b458]1226
[984a9ba]1227 async_get_call(call);
[a35b458]1228
[fafb8e5]1229 if (ipc_get_imethod(call) != IPC_M_SHARE_IN)
[47b7006]1230 return false;
[a35b458]1231
[fafb8e5]1232 *size = (size_t) ipc_get_arg1(call);
[47b7006]1233 return true;
[0da4e41]1234}
1235
1236/** Wrapper for answering the IPC_M_SHARE_IN calls using the async framework.
1237 *
[fbcdeb8]1238 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_IN
[47b7006]1239 * calls so that the user doesn't have to remember the meaning of each IPC
1240 * argument.
[0da4e41]1241 *
[f8048d1]1242 * @param call IPC_M_SHARE_IN call to answer.
[984a9ba]1243 * @param src Source address space base.
1244 * @param flags Flags to be used for sharing. Bits can be only cleared.
[47b7006]1245 *
1246 * @return Zero on success or a value from @ref errno.h on failure.
[0da4e41]1247 *
1248 */
[984a9ba]1249errno_t async_share_in_finalize(ipc_call_t *call, void *src, unsigned int flags)
[0da4e41]1250{
[984a9ba]1251 assert(call);
1252
[d57c7c2]1253 cap_call_handle_t chandle = call->cap_handle;
1254 assert(chandle != CAP_NIL);
1255 call->cap_handle = CAP_NIL;
1256
1257 return ipc_answer_2(chandle, EOK, (sysarg_t) src, (sysarg_t) flags);
[0da4e41]1258}
1259
1260/** Wrapper for receiving the IPC_M_SHARE_OUT calls using the async framework.
1261 *
[47b7006]1262 * This wrapper only makes it more comfortable to receive IPC_M_SHARE_OUT
1263 * calls so that the user doesn't have to remember the meaning of each IPC
1264 * argument.
[0da4e41]1265 *
1266 * So far, this wrapper is to be used from within a connection fibril.
1267 *
[984a9ba]1268 * @param call Storage for the data of the IPC_M_SHARE_OUT call.
1269 * @param size Storage for the source address space area size.
1270 * @param flags Storage for the sharing flags.
[47b7006]1271 *
1272 * @return True on success, false on failure.
[0da4e41]1273 *
1274 */
[984a9ba]1275bool async_share_out_receive(ipc_call_t *call, size_t *size,
[01c3bb4]1276 unsigned int *flags)
[0da4e41]1277{
[984a9ba]1278 assert(call);
[0da4e41]1279 assert(size);
1280 assert(flags);
[a35b458]1281
[984a9ba]1282 async_get_call(call);
[a35b458]1283
[fafb8e5]1284 if (ipc_get_imethod(call) != IPC_M_SHARE_OUT)
[47b7006]1285 return false;
[a35b458]1286
[fafb8e5]1287 *size = (size_t) ipc_get_arg2(call);
1288 *flags = (unsigned int) ipc_get_arg3(call);
[47b7006]1289 return true;
[0da4e41]1290}
1291
1292/** Wrapper for answering the IPC_M_SHARE_OUT calls using the async framework.
1293 *
[47b7006]1294 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT
1295 * calls so that the user doesn't have to remember the meaning of each IPC
1296 * argument.
[0da4e41]1297 *
[f8048d1]1298 * @param call IPC_M_SHARE_OUT call to answer.
[984a9ba]1299 * @param dst Address of the storage for the destination address space area
1300 * base address.
[47b7006]1301 *
[01c3bb4]1302 * @return Zero on success or a value from @ref errno.h on failure.
[0da4e41]1303 *
1304 */
[984a9ba]1305errno_t async_share_out_finalize(ipc_call_t *call, void **dst)
[0da4e41]1306{
[984a9ba]1307 assert(call);
[0da4e41]1308
[d57c7c2]1309 cap_call_handle_t chandle = call->cap_handle;
1310 assert(chandle != CAP_NIL);
1311 call->cap_handle = CAP_NIL;
1312
1313 return ipc_answer_2(chandle, EOK, (sysarg_t) __progsymbols.end,
[984a9ba]1314 (sysarg_t) dst);
[d768d4c8]1315}
1316
1317/** Wrapper for receiving the IPC_M_DATA_READ calls using the async framework.
1318 *
1319 * This wrapper only makes it more comfortable to receive IPC_M_DATA_READ
1320 * calls so that the user doesn't have to remember the meaning of each IPC
1321 * argument.
1322 *
1323 * So far, this wrapper is to be used from within a connection fibril.
1324 *
[984a9ba]1325 * @param call Storage for the data of the IPC_M_DATA_READ.
1326 * @param size Storage for the maximum size. Can be NULL.
[d768d4c8]1327 *
1328 * @return True on success, false on failure.
1329 *
1330 */
[984a9ba]1331bool async_data_read_receive(ipc_call_t *call, size_t *size)
[0da4e41]1332{
[984a9ba]1333 assert(call);
[a35b458]1334
[984a9ba]1335 async_get_call(call);
[a35b458]1336
[fafb8e5]1337 if (ipc_get_imethod(call) != IPC_M_DATA_READ)
[47b7006]1338 return false;
[a35b458]1339
[0da4e41]1340 if (size)
[fafb8e5]1341 *size = (size_t) ipc_get_arg2(call);
[a35b458]1342
[47b7006]1343 return true;
[0da4e41]1344}
1345
1346/** Wrapper for answering the IPC_M_DATA_READ calls using the async framework.
1347 *
[47b7006]1348 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
1349 * calls so that the user doesn't have to remember the meaning of each IPC
1350 * argument.
[0da4e41]1351 *
[984a9ba]1352 * @param call IPC_M_DATA_READ call to answer.
1353 * @param src Source address for the IPC_M_DATA_READ call.
1354 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than
1355 * the maximum size announced by the sender.
[47b7006]1356 *
[01c3bb4]1357 * @return Zero on success or a value from @ref errno.h on failure.
[0da4e41]1358 *
1359 */
[984a9ba]1360errno_t async_data_read_finalize(ipc_call_t *call, const void *src, size_t size)
[0da4e41]1361{
[984a9ba]1362 assert(call);
1363
[d57c7c2]1364 cap_call_handle_t chandle = call->cap_handle;
1365 assert(chandle != CAP_NIL);
1366 call->cap_handle = CAP_NIL;
1367
1368 return ipc_answer_2(chandle, EOK, (sysarg_t) src, (sysarg_t) size);
[0da4e41]1369}
1370
[b4cbef1]1371/** Wrapper for forwarding any read request
1372 *
1373 */
[4f13e19]1374static errno_t async_data_read_forward_fast(async_exch_t *exch, sysarg_t imethod,
[79ae36dd]1375 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
1376 ipc_call_t *dataptr)
[b4cbef1]1377{
[79ae36dd]1378 if (exch == NULL)
1379 return ENOENT;
[a35b458]1380
[984a9ba]1381 ipc_call_t call;
1382 if (!async_data_read_receive(&call, NULL)) {
1383 async_answer_0(&call, EINVAL);
[b4cbef1]1384 return EINVAL;
1385 }
[a35b458]1386
[4f13e19]1387 aid_t msg = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
[b4cbef1]1388 dataptr);
1389 if (msg == 0) {
[984a9ba]1390 async_answer_0(&call, EINVAL);
[b4cbef1]1391 return EINVAL;
1392 }
[a35b458]1393
[984a9ba]1394 errno_t retval = ipc_forward_fast(call.cap_handle, exch->phone, 0, 0, 0,
[b4cbef1]1395 IPC_FF_ROUTE_FROM_ME);
1396 if (retval != EOK) {
[ab9f443]1397 async_forget(msg);
[984a9ba]1398 async_answer_0(&call, retval);
[b4cbef1]1399 return retval;
1400 }
[a35b458]1401
[b7fd2a0]1402 errno_t rc;
[b4cbef1]1403 async_wait_for(msg, &rc);
[a35b458]1404
[b7fd2a0]1405 return (errno_t) rc;
[b4cbef1]1406}
1407
[4f13e19]1408errno_t async_data_read_forward_0_0(async_exch_t *exch, sysarg_t imethod)
1409{
1410 return async_data_read_forward_fast(exch, imethod, 0, 0, 0, 0, NULL);
1411}
1412
1413errno_t async_data_read_forward_1_0(async_exch_t *exch, sysarg_t imethod,
1414 sysarg_t arg1)
1415{
1416 return async_data_read_forward_fast(exch, imethod, arg1, 0, 0, 0, NULL);
1417}
1418
1419errno_t async_data_read_forward_2_0(async_exch_t *exch, sysarg_t imethod,
1420 sysarg_t arg1, sysarg_t arg2)
1421{
1422 return async_data_read_forward_fast(exch, imethod, arg1, arg2, 0,
1423 0, NULL);
1424}
1425
1426errno_t async_data_read_forward_3_0(async_exch_t *exch, sysarg_t imethod,
1427 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
1428{
1429 return async_data_read_forward_fast(exch, imethod, arg1, arg2, arg3,
1430 0, NULL);
1431}
1432
1433errno_t async_data_read_forward_4_0(async_exch_t *exch, sysarg_t imethod,
1434 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
1435{
1436 return async_data_read_forward_fast(exch, imethod, arg1, arg2, arg3,
1437 arg4, NULL);
1438}
1439
1440errno_t async_data_read_forward_0_1(async_exch_t *exch, sysarg_t imethod,
1441 ipc_call_t *dataptr)
1442{
1443 return async_data_read_forward_fast(exch, imethod, 0, 0, 0,
1444 0, dataptr);
1445}
1446
1447errno_t async_data_read_forward_1_1(async_exch_t *exch, sysarg_t imethod,
1448 sysarg_t arg1, ipc_call_t *dataptr)
1449{
1450 return async_data_read_forward_fast(exch, imethod, arg1, 0, 0,
1451 0, dataptr);
1452}
1453
1454errno_t async_data_read_forward_2_1(async_exch_t *exch, sysarg_t imethod,
1455 sysarg_t arg1, sysarg_t arg2, ipc_call_t *dataptr)
1456{
1457 return async_data_read_forward_fast(exch, imethod, arg1, arg2, 0,
1458 0, dataptr);
1459}
1460
1461errno_t async_data_read_forward_3_1(async_exch_t *exch, sysarg_t imethod,
1462 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, ipc_call_t *dataptr)
1463{
1464 return async_data_read_forward_fast(exch, imethod, arg1, arg2, arg3,
1465 0, dataptr);
1466}
1467
1468errno_t async_data_read_forward_4_1(async_exch_t *exch, sysarg_t imethod,
1469 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
1470 ipc_call_t *dataptr)
1471{
1472 return async_data_read_forward_fast(exch, imethod, arg1, arg2, arg3,
1473 arg4, dataptr);
1474}
1475
[0da4e41]1476/** Wrapper for receiving the IPC_M_DATA_WRITE calls using the async framework.
1477 *
[47b7006]1478 * This wrapper only makes it more comfortable to receive IPC_M_DATA_WRITE
1479 * calls so that the user doesn't have to remember the meaning of each IPC
1480 * argument.
[0da4e41]1481 *
1482 * So far, this wrapper is to be used from within a connection fibril.
1483 *
[984a9ba]1484 * @param call Storage for the data of the IPC_M_DATA_WRITE.
1485 * @param size Storage for the suggested size. May be NULL.
[5ae1c51]1486 *
1487 * @return True on success, false on failure.
1488 *
1489 */
[984a9ba]1490bool async_data_write_receive(ipc_call_t *call, size_t *size)
[0da4e41]1491{
[984a9ba]1492 assert(call);
[a35b458]1493
[984a9ba]1494 async_get_call(call);
[a35b458]1495
[fafb8e5]1496 if (ipc_get_imethod(call) != IPC_M_DATA_WRITE)
[47b7006]1497 return false;
[a35b458]1498
[0da4e41]1499 if (size)
[fafb8e5]1500 *size = (size_t) ipc_get_arg2(call);
[a35b458]1501
[47b7006]1502 return true;
[0da4e41]1503}
1504
1505/** Wrapper for answering the IPC_M_DATA_WRITE calls using the async framework.
1506 *
[47b7006]1507 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE
1508 * calls so that the user doesn't have to remember the meaning of each IPC
1509 * argument.
[0da4e41]1510 *
[984a9ba]1511 * @param call IPC_M_DATA_WRITE call to answer.
1512 * @param dst Final destination address for the IPC_M_DATA_WRITE call.
1513 * @param size Final size for the IPC_M_DATA_WRITE call.
[b4cbef1]1514 *
[01c3bb4]1515 * @return Zero on success or a value from @ref errno.h on failure.
[0da4e41]1516 *
1517 */
[984a9ba]1518errno_t async_data_write_finalize(ipc_call_t *call, void *dst, size_t size)
[0da4e41]1519{
[984a9ba]1520 assert(call);
1521
1522 return async_answer_2(call, EOK, (sysarg_t) dst, (sysarg_t) size);
[0da4e41]1523}
1524
[eda925a]1525/** Wrapper for receiving binary data or strings
[8aa42e3]1526 *
1527 * This wrapper only makes it more comfortable to use async_data_write_*
[eda925a]1528 * functions to receive binary data or strings.
[8aa42e3]1529 *
[472c09d]1530 * @param data Pointer to data pointer (which should be later disposed
1531 * by free()). If the operation fails, the pointer is not
1532 * touched.
[eda925a]1533 * @param nullterm If true then the received data is always zero terminated.
1534 * This also causes to allocate one extra byte beyond the
1535 * raw transmitted data.
[b4cbef1]1536 * @param min_size Minimum size (in bytes) of the data to receive.
[472c09d]1537 * @param max_size Maximum size (in bytes) of the data to receive. 0 means
1538 * no limit.
[eda925a]1539 * @param granulariy If non-zero then the size of the received data has to
[472c09d]1540 * be divisible by this value.
1541 * @param received If not NULL, the size of the received data is stored here.
[8aa42e3]1542 *
1543 * @return Zero on success or a value from @ref errno.h on failure.
1544 *
1545 */
[b7fd2a0]1546errno_t async_data_write_accept(void **data, const bool nullterm,
[eda925a]1547 const size_t min_size, const size_t max_size, const size_t granularity,
1548 size_t *received)
[8aa42e3]1549{
[79ae36dd]1550 assert(data);
[a35b458]1551
[984a9ba]1552 ipc_call_t call;
[8aa42e3]1553 size_t size;
[984a9ba]1554 if (!async_data_write_receive(&call, &size)) {
1555 async_answer_0(&call, EINVAL);
[8aa42e3]1556 return EINVAL;
1557 }
[a35b458]1558
[b4cbef1]1559 if (size < min_size) {
[984a9ba]1560 async_answer_0(&call, EINVAL);
[b4cbef1]1561 return EINVAL;
1562 }
[a35b458]1563
[8aa42e3]1564 if ((max_size > 0) && (size > max_size)) {
[984a9ba]1565 async_answer_0(&call, EINVAL);
[8aa42e3]1566 return EINVAL;
1567 }
[a35b458]1568
[472c09d]1569 if ((granularity > 0) && ((size % granularity) != 0)) {
[984a9ba]1570 async_answer_0(&call, EINVAL);
[472c09d]1571 return EINVAL;
1572 }
[a35b458]1573
[57dea62]1574 void *arg_data;
[a35b458]1575
[eda925a]1576 if (nullterm)
[57dea62]1577 arg_data = malloc(size + 1);
[eda925a]1578 else
[57dea62]1579 arg_data = malloc(size);
[a35b458]1580
[57dea62]1581 if (arg_data == NULL) {
[984a9ba]1582 async_answer_0(&call, ENOMEM);
[8aa42e3]1583 return ENOMEM;
1584 }
[a35b458]1585
[984a9ba]1586 errno_t rc = async_data_write_finalize(&call, arg_data, size);
[8aa42e3]1587 if (rc != EOK) {
[57dea62]1588 free(arg_data);
[8aa42e3]1589 return rc;
1590 }
[a35b458]1591
[eda925a]1592 if (nullterm)
[57dea62]1593 ((char *) arg_data)[size] = 0;
[a35b458]1594
[57dea62]1595 *data = arg_data;
[472c09d]1596 if (received != NULL)
1597 *received = size;
[a35b458]1598
[8aa42e3]1599 return EOK;
1600}
1601
[b4cbef1]1602/** Wrapper for voiding any data that is about to be received
1603 *
1604 * This wrapper can be used to void any pending data
1605 *
1606 * @param retval Error value from @ref errno.h to be returned to the caller.
1607 *
1608 */
[b7fd2a0]1609void async_data_write_void(errno_t retval)
[b4cbef1]1610{
[984a9ba]1611 ipc_call_t call;
1612 async_data_write_receive(&call, NULL);
1613 async_answer_0(&call, retval);
[b4cbef1]1614}
1615
1616/** Wrapper for forwarding any data that is about to be received
1617 *
1618 */
[4f13e19]1619static errno_t async_data_write_forward_fast(async_exch_t *exch,
1620 sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
1621 sysarg_t arg4, ipc_call_t *dataptr)
[b4cbef1]1622{
[79ae36dd]1623 if (exch == NULL)
1624 return ENOENT;
[a35b458]1625
[984a9ba]1626 ipc_call_t call;
1627 if (!async_data_write_receive(&call, NULL)) {
1628 async_answer_0(&call, EINVAL);
[b4cbef1]1629 return EINVAL;
1630 }
[a35b458]1631
[4f13e19]1632 aid_t msg = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
[b4cbef1]1633 dataptr);
1634 if (msg == 0) {
[984a9ba]1635 async_answer_0(&call, EINVAL);
[b4cbef1]1636 return EINVAL;
1637 }
[a35b458]1638
[984a9ba]1639 errno_t retval = ipc_forward_fast(call.cap_handle, exch->phone, 0, 0, 0,
[b4cbef1]1640 IPC_FF_ROUTE_FROM_ME);
1641 if (retval != EOK) {
[ab9f443]1642 async_forget(msg);
[984a9ba]1643 async_answer_0(&call, retval);
[b4cbef1]1644 return retval;
1645 }
[a35b458]1646
[b7fd2a0]1647 errno_t rc;
[b4cbef1]1648 async_wait_for(msg, &rc);
[a35b458]1649
[b7fd2a0]1650 return (errno_t) rc;
[b4cbef1]1651}
1652
[4f13e19]1653errno_t async_data_write_forward_0_0(async_exch_t *exch, sysarg_t imethod)
1654{
1655 return async_data_write_forward_fast(exch, imethod, 0, 0, 0,
1656 0, NULL);
1657}
1658
1659errno_t async_data_write_forward_1_0(async_exch_t *exch, sysarg_t imethod,
1660 sysarg_t arg1)
1661{
1662 return async_data_write_forward_fast(exch, imethod, arg1, 0, 0,
1663 0, NULL);
1664}
1665
1666errno_t async_data_write_forward_2_0(async_exch_t *exch, sysarg_t imethod,
1667 sysarg_t arg1, sysarg_t arg2)
1668{
1669 return async_data_write_forward_fast(exch, imethod, arg1, arg2, 0,
1670 0, NULL);
1671}
1672
1673errno_t async_data_write_forward_3_0(async_exch_t *exch, sysarg_t imethod,
1674 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
1675{
1676 return async_data_write_forward_fast(exch, imethod, arg1, arg2, arg3,
1677 0, NULL);
1678}
1679
1680errno_t async_data_write_forward_4_0(async_exch_t *exch, sysarg_t imethod,
1681 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
1682{
1683 return async_data_write_forward_fast(exch, imethod, arg1, arg2, arg3,
1684 arg4, NULL);
1685}
1686
1687errno_t async_data_write_forward_0_1(async_exch_t *exch, sysarg_t imethod,
1688 ipc_call_t *dataptr)
1689{
1690 return async_data_write_forward_fast(exch, imethod, 0, 0, 0,
1691 0, dataptr);
1692}
1693
1694errno_t async_data_write_forward_1_1(async_exch_t *exch, sysarg_t imethod,
1695 sysarg_t arg1, ipc_call_t *dataptr)
1696{
1697 return async_data_write_forward_fast(exch, imethod, arg1, 0, 0,
1698 0, dataptr);
1699}
1700
1701errno_t async_data_write_forward_2_1(async_exch_t *exch, sysarg_t imethod,
1702 sysarg_t arg1, sysarg_t arg2, ipc_call_t *dataptr)
1703{
1704 return async_data_write_forward_fast(exch, imethod, arg1, arg2, 0,
1705 0, dataptr);
1706}
1707
1708errno_t async_data_write_forward_3_1(async_exch_t *exch, sysarg_t imethod,
1709 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, ipc_call_t *dataptr)
1710{
1711 return async_data_write_forward_fast(exch, imethod, arg1, arg2, arg3,
1712 0, dataptr);
1713}
1714
1715errno_t async_data_write_forward_4_1(async_exch_t *exch, sysarg_t imethod,
1716 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
1717 ipc_call_t *dataptr)
1718{
1719 return async_data_write_forward_fast(exch, imethod, arg1, arg2, arg3,
1720 arg4, dataptr);
1721}
1722
[79ae36dd]1723/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
1724 *
1725 * If the current call is IPC_M_CONNECT_TO_ME then a new
1726 * async session is created for the accepted phone.
1727 *
1728 * @param mgmt Exchange management style.
1729 *
[8869f7b]1730 * @return New async session.
1731 * @return NULL on failure.
[79ae36dd]1732 *
1733 */
1734async_sess_t *async_callback_receive(exch_mgmt_t mgmt)
1735{
1736 /* Accept the phone */
1737 ipc_call_t call;
[984a9ba]1738 async_get_call(&call);
1739
[fafb8e5]1740 cap_phone_handle_t phandle = (cap_handle_t) ipc_get_arg5(&call);
[a35b458]1741
[fafb8e5]1742 if ((ipc_get_imethod(&call) != IPC_M_CONNECT_TO_ME) ||
[bb97118]1743 !cap_handle_valid((phandle))) {
[984a9ba]1744 async_answer_0(&call, EINVAL);
[79ae36dd]1745 return NULL;
1746 }
[a35b458]1747
[498ced1]1748 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
[79ae36dd]1749 if (sess == NULL) {
[984a9ba]1750 async_answer_0(&call, ENOMEM);
[79ae36dd]1751 return NULL;
1752 }
[a35b458]1753
[566992e1]1754 sess->iface = 0;
[79ae36dd]1755 sess->mgmt = mgmt;
[01c3bb4]1756 sess->phone = phandle;
[a35b458]1757
[58cbf8d5]1758 fibril_mutex_initialize(&sess->remote_state_mtx);
[79ae36dd]1759 list_initialize(&sess->exch_list);
1760 fibril_mutex_initialize(&sess->mutex);
[a35b458]1761
[79ae36dd]1762 /* Acknowledge the connected phone */
[984a9ba]1763 async_answer_0(&call, EOK);
[a35b458]1764
[79ae36dd]1765 return sess;
1766}
1767
[8869f7b]1768/** Wrapper for receiving the IPC_M_CONNECT_TO_ME calls.
1769 *
1770 * If the call is IPC_M_CONNECT_TO_ME then a new
1771 * async session is created. However, the phone is
1772 * not accepted automatically.
1773 *
1774 * @param mgmt Exchange management style.
1775 * @param call Call data.
1776 *
1777 * @return New async session.
1778 * @return NULL on failure.
1779 * @return NULL if the call is not IPC_M_CONNECT_TO_ME.
1780 *
1781 */
1782async_sess_t *async_callback_receive_start(exch_mgmt_t mgmt, ipc_call_t *call)
1783{
[fafb8e5]1784 cap_phone_handle_t phandle = (cap_handle_t) ipc_get_arg5(call);
[a35b458]1785
[fafb8e5]1786 if ((ipc_get_imethod(call) != IPC_M_CONNECT_TO_ME) ||
[bb97118]1787 !cap_handle_valid((phandle)))
[8869f7b]1788 return NULL;
[a35b458]1789
[498ced1]1790 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
[8869f7b]1791 if (sess == NULL)
1792 return NULL;
[a35b458]1793
[566992e1]1794 sess->iface = 0;
[8869f7b]1795 sess->mgmt = mgmt;
[01c3bb4]1796 sess->phone = phandle;
[a35b458]1797
[58cbf8d5]1798 fibril_mutex_initialize(&sess->remote_state_mtx);
[8869f7b]1799 list_initialize(&sess->exch_list);
1800 fibril_mutex_initialize(&sess->mutex);
[a35b458]1801
[8869f7b]1802 return sess;
1803}
1804
[984a9ba]1805bool async_state_change_receive(ipc_call_t *call)
[2c4aa39]1806{
[984a9ba]1807 assert(call);
[a35b458]1808
[984a9ba]1809 async_get_call(call);
[a35b458]1810
[fafb8e5]1811 if (ipc_get_imethod(call) != IPC_M_STATE_CHANGE_AUTHORIZE)
[2c4aa39]1812 return false;
[a35b458]1813
[2c4aa39]1814 return true;
1815}
1816
[984a9ba]1817errno_t async_state_change_finalize(ipc_call_t *call, async_exch_t *other_exch)
[2c4aa39]1818{
[984a9ba]1819 assert(call);
1820
[bb97118]1821 return async_answer_1(call, EOK, cap_handle_raw(other_exch->phone));
[2c4aa39]1822}
1823
[6b96dc06]1824__noreturn void async_manager(void)
[d73d992]1825{
[514d561]1826 fibril_event_t ever = FIBRIL_EVENT_INIT;
1827 fibril_wait_for(&ever);
[d73d992]1828 __builtin_unreachable();
1829}
1830
[a46da63]1831/** @}
[b2951e2]1832 */
Note: See TracBrowser for help on using the repository browser.