source: mainline/uspace/lib/c/generic/async/client.c@ b42fa76

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b42fa76 was 01900b6, checked in by Martin Decky <martin@…>, 5 years ago

Use an optional output argument instead of errno to propagate the error

The use of errno is troublesome in all other than top-level library
functions since the value in errno might get overwritten by subsequent
inner calls on the error path (e.g. cleanup, deallocation, etc.). The
optional output argument makes it possible to explicitly ignore the
error code if it is not needed, but still to pass it reliably back to
the original caller.

This change affecs async_connect_me_to(),
async_connect_me_to_blocking(), async_connect_kbox(), service_connect(),
service_connect_blocking() and loader_connect().

  • Property mode set to 100644
File size: 37.2 KB
RevLine 
[49a796f1]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/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35/**
36 * Asynchronous library
37 *
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.
41 *
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.
45 *
46 * Example of use (pseudo C):
47 *
48 * 1) Multithreaded client application
49 *
50 * fibril_create(fibril1, ...);
51 * fibril_create(fibril2, ...);
52 * ...
53 *
54 * int fibril1(void *arg)
55 * {
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 *
66 * async_wait_for(c1);
67 * async_wait_for(c2);
68 * ...
69 * }
70 *
71 *
72 * 2) Multithreaded server application
73 *
74 * main()
75 * {
76 * async_manager();
77 * }
78 *
79 * port_handler(ichandle, *icall)
80 * {
81 * if (want_refuse) {
82 * async_answer_0(ichandle, ELIMIT);
83 * return;
84 * }
85 * async_answer_0(ichandle, EOK);
86 *
87 * chandle = async_get_call(&call);
88 * somehow_handle_the_call(chandle, call);
89 * async_answer_2(chandle, 1, 2, 3);
90 *
91 * chandle = async_get_call(&call);
92 * ...
93 * }
94 *
95 */
96
[4805495]97#define _LIBC_ASYNC_C_
[49a796f1]98#include <ipc/ipc.h>
99#include <async.h>
100#include "../private/async.h"
[9f272d9]101#include "../private/ns.h"
[4805495]102#undef _LIBC_ASYNC_C_
[49a796f1]103
104#include <ipc/irq.h>
105#include <ipc/event.h>
106#include <fibril.h>
107#include <adt/hash_table.h>
108#include <adt/hash.h>
109#include <adt/list.h>
110#include <assert.h>
111#include <errno.h>
[bd41ac52]112#include <time.h>
[05882233]113#include <barrier.h>
[49a796f1]114#include <stdbool.h>
115#include <stdlib.h>
116#include <mem.h>
117#include <stdlib.h>
118#include <macros.h>
119#include <as.h>
120#include <abi/mm/as.h>
121#include "../private/libc.h"
[d73d992]122#include "../private/fibril.h"
[49a796f1]123
[45c8eea]124static fibril_rmutex_t message_mutex;
[8080262]125
[49a796f1]126/** Naming service session */
[9f272d9]127async_sess_t session_ns;
[49a796f1]128
129/** Message data */
130typedef struct {
[514d561]131 fibril_event_t received;
[49a796f1]132
133 /** If reply was received. */
134 bool done;
135
136 /** If the message / reply should be discarded on arrival. */
137 bool forget;
138
139 /** Pointer to where the answer data is stored. */
140 ipc_call_t *dataptr;
141
142 errno_t retval;
143} amsg_t;
144
145static amsg_t *amsg_create(void)
146{
[514d561]147 return calloc(1, sizeof(amsg_t));
[49a796f1]148}
149
150static void amsg_destroy(amsg_t *msg)
151{
152 free(msg);
153}
154
155/** Mutex protecting inactive_exch_list and avail_phone_cv.
156 *
157 */
158static FIBRIL_MUTEX_INITIALIZE(async_sess_mutex);
159
160/** List of all currently inactive exchanges.
161 *
162 */
163static LIST_INITIALIZE(inactive_exch_list);
164
165/** Condition variable to wait for a phone to become available.
166 *
167 */
168static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
169
170/** Initialize the async framework.
171 *
172 */
173void __async_client_init(void)
174{
[45c8eea]175 if (fibril_rmutex_initialize(&message_mutex) != EOK)
176 abort();
177
[9f272d9]178 session_ns.iface = 0;
179 session_ns.mgmt = EXCHANGE_ATOMIC;
180 session_ns.phone = PHONE_NS;
181 session_ns.arg1 = 0;
182 session_ns.arg2 = 0;
183 session_ns.arg3 = 0;
184
185 fibril_mutex_initialize(&session_ns.remote_state_mtx);
186 session_ns.remote_state_data = NULL;
187
188 list_initialize(&session_ns.exch_list);
189 fibril_mutex_initialize(&session_ns.mutex);
[498ced1]190 session_ns.exchanges = 0;
[49a796f1]191}
192
[25f6bddb]193void __async_client_fini(void)
194{
195 fibril_rmutex_destroy(&message_mutex);
196}
197
[49a796f1]198/** Reply received callback.
199 *
200 * This function is called whenever a reply for an asynchronous message sent out
201 * by the asynchronous framework is received.
202 *
203 * Notify the fibril which is waiting for this message that it has arrived.
204 *
205 * @param arg Pointer to the asynchronous message record.
206 * @param retval Value returned in the answer.
207 * @param data Call data of the answer.
208 *
209 */
[d054ad3]210void async_reply_received(ipc_call_t *data)
[49a796f1]211{
[6769005]212 amsg_t *msg = (amsg_t *) data->answer_label;
[d054ad3]213 if (!msg)
214 return;
[49a796f1]215
[8080262]216 fibril_rmutex_lock(&message_mutex);
[49a796f1]217
[fafb8e5]218 msg->retval = ipc_get_retval(data);
[49a796f1]219
[514d561]220 /* Copy data inside lock, just in case the call was detached */
[49a796f1]221 if ((msg->dataptr) && (data))
222 *msg->dataptr = *data;
223
224 msg->done = true;
225
226 if (msg->forget) {
227 amsg_destroy(msg);
[514d561]228 } else {
229 fibril_notify(&msg->received);
[49a796f1]230 }
231
[8080262]232 fibril_rmutex_unlock(&message_mutex);
[49a796f1]233}
234
235/** Send message and return id of the sent message.
236 *
237 * The return value can be used as input for async_wait() to wait for
238 * completion.
239 *
240 * @param exch Exchange for sending the message.
241 * @param imethod Service-defined interface and method.
242 * @param arg1 Service-defined payload argument.
243 * @param arg2 Service-defined payload argument.
244 * @param arg3 Service-defined payload argument.
245 * @param arg4 Service-defined payload argument.
246 * @param dataptr If non-NULL, storage where the reply data will be stored.
247 *
248 * @return Hash of the sent message or 0 on error.
249 *
250 */
[4f13e19]251static aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
[49a796f1]252 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
253{
254 if (exch == NULL)
255 return 0;
256
257 amsg_t *msg = amsg_create();
258 if (msg == NULL)
259 return 0;
260
261 msg->dataptr = dataptr;
262
[d054ad3]263 errno_t rc = ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3,
264 arg4, msg);
265 if (rc != EOK) {
266 msg->retval = rc;
267 msg->done = true;
268 }
[49a796f1]269
270 return (aid_t) msg;
271}
272
273/** Send message and return id of the sent message
274 *
275 * The return value can be used as input for async_wait() to wait for
276 * completion.
277 *
278 * @param exch Exchange for sending the message.
279 * @param imethod Service-defined interface and method.
280 * @param arg1 Service-defined payload argument.
281 * @param arg2 Service-defined payload argument.
282 * @param arg3 Service-defined payload argument.
283 * @param arg4 Service-defined payload argument.
284 * @param arg5 Service-defined payload argument.
285 * @param dataptr If non-NULL, storage where the reply data will be
286 * stored.
287 *
288 * @return Hash of the sent message or 0 on error.
289 *
290 */
[4f13e19]291static aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
[49a796f1]292 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
293 ipc_call_t *dataptr)
294{
295 if (exch == NULL)
296 return 0;
297
298 amsg_t *msg = amsg_create();
299 if (msg == NULL)
300 return 0;
301
302 msg->dataptr = dataptr;
303
[d054ad3]304 errno_t rc = ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3,
305 arg4, arg5, msg);
306 if (rc != EOK) {
307 msg->retval = rc;
308 msg->done = true;
309 }
[49a796f1]310
311 return (aid_t) msg;
312}
313
[4f13e19]314aid_t async_send_0(async_exch_t *exch, sysarg_t imethod, ipc_call_t *dataptr)
315{
316 return async_send_fast(exch, imethod, 0, 0, 0, 0, dataptr);
317}
318
319aid_t async_send_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
320 ipc_call_t *dataptr)
321{
322 return async_send_fast(exch, imethod, arg1, 0, 0, 0, dataptr);
323}
324
325aid_t async_send_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
326 sysarg_t arg2, ipc_call_t *dataptr)
327{
328 return async_send_fast(exch, imethod, arg1, arg2, 0, 0, dataptr);
329}
330
331aid_t async_send_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
332 sysarg_t arg2, sysarg_t arg3, ipc_call_t *dataptr)
333{
334 return async_send_fast(exch, imethod, arg1, arg2, arg3, 0, dataptr);
335}
336
337aid_t async_send_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
338 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
339{
340 return async_send_fast(exch, imethod, arg1, arg2, arg3, arg4, dataptr);
341}
342
343aid_t async_send_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
344 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
345 ipc_call_t *dataptr)
346{
347 return async_send_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5,
348 dataptr);
349}
350
[49a796f1]351/** Wait for a message sent by the async framework.
352 *
353 * @param amsgid Hash of the message to wait for.
354 * @param retval Pointer to storage where the retval of the answer will
355 * be stored.
356 *
357 */
358void async_wait_for(aid_t amsgid, errno_t *retval)
359{
[bd9e868]360 if (amsgid == 0) {
361 if (retval)
362 *retval = ENOMEM;
363 return;
364 }
[49a796f1]365
366 amsg_t *msg = (amsg_t *) amsgid;
[514d561]367 fibril_wait_for(&msg->received);
[49a796f1]368
369 if (retval)
370 *retval = msg->retval;
371
372 amsg_destroy(msg);
373}
374
375/** Wait for a message sent by the async framework, timeout variant.
376 *
377 * If the wait times out, the caller may choose to either wait again by calling
378 * async_wait_for() or async_wait_timeout(), or forget the message via
379 * async_forget().
380 *
381 * @param amsgid Hash of the message to wait for.
382 * @param retval Pointer to storage where the retval of the answer will
383 * be stored.
384 * @param timeout Timeout in microseconds.
385 *
386 * @return Zero on success, ETIMEOUT if the timeout has expired.
387 *
388 */
[bd41ac52]389errno_t async_wait_timeout(aid_t amsgid, errno_t *retval, usec_t timeout)
[49a796f1]390{
[bd9e868]391 if (amsgid == 0) {
392 if (retval)
393 *retval = ENOMEM;
394 return EOK;
395 }
[49a796f1]396
397 amsg_t *msg = (amsg_t *) amsgid;
398
399 /*
400 * Negative timeout is converted to zero timeout to avoid
401 * using tv_add with negative augmenter.
402 */
403 if (timeout < 0)
404 timeout = 0;
405
[bd41ac52]406 struct timespec expires;
[514d561]407 getuptime(&expires);
[bd41ac52]408 ts_add_diff(&expires, USEC2NSEC(timeout));
[49a796f1]409
[514d561]410 errno_t rc = fibril_wait_timeout(&msg->received, &expires);
411 if (rc != EOK)
412 return rc;
[49a796f1]413
414 if (retval)
415 *retval = msg->retval;
416
417 amsg_destroy(msg);
418
[514d561]419 return EOK;
[49a796f1]420}
421
422/** Discard the message / reply on arrival.
423 *
424 * The message will be marked to be discarded once the reply arrives in
425 * reply_received(). It is not allowed to call async_wait_for() or
426 * async_wait_timeout() on this message after a call to this function.
427 *
428 * @param amsgid Hash of the message to forget.
429 */
430void async_forget(aid_t amsgid)
431{
[bd9e868]432 if (amsgid == 0)
433 return;
434
[49a796f1]435 amsg_t *msg = (amsg_t *) amsgid;
436
437 assert(!msg->forget);
438
[8080262]439 fibril_rmutex_lock(&message_mutex);
[49a796f1]440
441 if (msg->done) {
442 amsg_destroy(msg);
443 } else {
444 msg->dataptr = NULL;
445 msg->forget = true;
446 }
447
[8080262]448 fibril_rmutex_unlock(&message_mutex);
[49a796f1]449}
450
451/** Pseudo-synchronous message sending - fast version.
452 *
453 * Send message asynchronously and return only after the reply arrives.
454 *
455 * This function can only transfer 4 register payload arguments. For
456 * transferring more arguments, see the slower async_req_slow().
457 *
458 * @param exch Exchange for sending the message.
459 * @param imethod Interface and method of the call.
460 * @param arg1 Service-defined payload argument.
461 * @param arg2 Service-defined payload argument.
462 * @param arg3 Service-defined payload argument.
463 * @param arg4 Service-defined payload argument.
464 * @param r1 If non-NULL, storage for the 1st reply argument.
465 * @param r2 If non-NULL, storage for the 2nd reply argument.
466 * @param r3 If non-NULL, storage for the 3rd reply argument.
467 * @param r4 If non-NULL, storage for the 4th reply argument.
468 * @param r5 If non-NULL, storage for the 5th reply argument.
469 *
470 * @return Return code of the reply or an error code.
471 *
472 */
[4f13e19]473static errno_t async_req_fast(async_exch_t *exch, sysarg_t imethod,
474 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4,
475 sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[49a796f1]476{
477 if (exch == NULL)
478 return ENOENT;
479
480 ipc_call_t result;
481 aid_t aid = async_send_4(exch, imethod, arg1, arg2, arg3, arg4,
482 &result);
483
484 errno_t rc;
485 async_wait_for(aid, &rc);
486
487 if (r1)
[fafb8e5]488 *r1 = ipc_get_arg1(&result);
[49a796f1]489
490 if (r2)
[fafb8e5]491 *r2 = ipc_get_arg2(&result);
[49a796f1]492
493 if (r3)
[fafb8e5]494 *r3 = ipc_get_arg3(&result);
[49a796f1]495
496 if (r4)
[fafb8e5]497 *r4 = ipc_get_arg4(&result);
[49a796f1]498
499 if (r5)
[fafb8e5]500 *r5 = ipc_get_arg5(&result);
[49a796f1]501
502 return rc;
503}
504
505/** Pseudo-synchronous message sending - slow version.
506 *
507 * Send message asynchronously and return only after the reply arrives.
508 *
509 * @param exch Exchange for sending the message.
510 * @param imethod Interface and method of the call.
511 * @param arg1 Service-defined payload argument.
512 * @param arg2 Service-defined payload argument.
513 * @param arg3 Service-defined payload argument.
514 * @param arg4 Service-defined payload argument.
515 * @param arg5 Service-defined payload argument.
516 * @param r1 If non-NULL, storage for the 1st reply argument.
517 * @param r2 If non-NULL, storage for the 2nd reply argument.
518 * @param r3 If non-NULL, storage for the 3rd reply argument.
519 * @param r4 If non-NULL, storage for the 4th reply argument.
520 * @param r5 If non-NULL, storage for the 5th reply argument.
521 *
522 * @return Return code of the reply or an error code.
523 *
524 */
[4f13e19]525static errno_t async_req_slow(async_exch_t *exch, sysarg_t imethod,
526 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
527 sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[49a796f1]528{
529 if (exch == NULL)
530 return ENOENT;
531
532 ipc_call_t result;
533 aid_t aid = async_send_5(exch, imethod, arg1, arg2, arg3, arg4, arg5,
534 &result);
535
536 errno_t rc;
537 async_wait_for(aid, &rc);
538
539 if (r1)
[fafb8e5]540 *r1 = ipc_get_arg1(&result);
[49a796f1]541
542 if (r2)
[fafb8e5]543 *r2 = ipc_get_arg2(&result);
[49a796f1]544
545 if (r3)
[fafb8e5]546 *r3 = ipc_get_arg3(&result);
[49a796f1]547
548 if (r4)
[fafb8e5]549 *r4 = ipc_get_arg4(&result);
[49a796f1]550
551 if (r5)
[fafb8e5]552 *r5 = ipc_get_arg5(&result);
[49a796f1]553
554 return rc;
555}
556
[4f13e19]557errno_t async_req_0_0(async_exch_t *exch, sysarg_t imethod)
558{
[b08fb02]559 return async_req_fast(exch, imethod, 0, 0, 0, 0, NULL, NULL, NULL, NULL,
560 NULL);
[4f13e19]561}
562
563errno_t async_req_0_1(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1)
564{
[b08fb02]565 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, NULL, NULL, NULL,
566 NULL);
[4f13e19]567}
568
[b08fb02]569errno_t async_req_0_2(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1,
570 sysarg_t *r2)
[4f13e19]571{
572 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, NULL, NULL, NULL);
573}
574
[b08fb02]575errno_t async_req_0_3(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1,
576 sysarg_t *r2, sysarg_t *r3)
[4f13e19]577{
578 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, NULL, NULL);
579}
580
[b08fb02]581errno_t async_req_0_4(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1,
582 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4)
[4f13e19]583{
584 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, r4, NULL);
585}
586
[b08fb02]587errno_t async_req_0_5(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1,
588 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[4f13e19]589{
590 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, r4, r5);
591}
592
593errno_t async_req_1_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
594{
[b08fb02]595 return async_req_fast(exch, imethod, arg1, 0, 0, 0, NULL, NULL, NULL, NULL,
596 NULL);
[4f13e19]597}
598
[b08fb02]599errno_t async_req_1_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
600 sysarg_t *r1)
[4f13e19]601{
[b08fb02]602 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, NULL, NULL, NULL,
603 NULL);
[4f13e19]604}
605
[b08fb02]606errno_t async_req_1_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
607 sysarg_t *r1, sysarg_t *r2)
[4f13e19]608{
[b08fb02]609 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, NULL, NULL,
610 NULL);
[4f13e19]611}
612
[b08fb02]613errno_t async_req_1_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
614 sysarg_t *r1, sysarg_t *r2, sysarg_t *r3)
[4f13e19]615{
[b08fb02]616 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, NULL,
617 NULL);
[4f13e19]618}
619
[b08fb02]620errno_t async_req_1_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
621 sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4)
[4f13e19]622{
623 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, r4, NULL);
624}
625
[b08fb02]626errno_t async_req_1_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
627 sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[4f13e19]628{
629 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, r4, r5);
630}
631
[b08fb02]632errno_t async_req_2_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
633 sysarg_t arg2)
[4f13e19]634{
[b08fb02]635 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, NULL, NULL, NULL,
636 NULL, NULL);
[4f13e19]637}
638
[b08fb02]639errno_t async_req_2_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
640 sysarg_t arg2, sysarg_t *r1)
[4f13e19]641{
[b08fb02]642 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, NULL, NULL,
643 NULL, NULL);
[4f13e19]644}
645
[b08fb02]646errno_t async_req_2_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
647 sysarg_t arg2, sysarg_t *r1, sysarg_t *r2)
[4f13e19]648{
[b08fb02]649 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, NULL,
650 NULL, NULL);
[4f13e19]651}
652
[b08fb02]653errno_t async_req_2_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
654 sysarg_t arg2, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3)
[4f13e19]655{
[b08fb02]656 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, NULL,
657 NULL);
[4f13e19]658}
659
[b08fb02]660errno_t async_req_2_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
661 sysarg_t arg2, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4)
[4f13e19]662{
[b08fb02]663 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, r4,
664 NULL);
[4f13e19]665}
666
[b08fb02]667errno_t async_req_2_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
668 sysarg_t arg2, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[4f13e19]669{
670 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, r4, r5);
671}
672
[b08fb02]673errno_t async_req_3_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
674 sysarg_t arg2, sysarg_t arg3)
[4f13e19]675{
[b08fb02]676 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, NULL, NULL, NULL,
677 NULL, NULL);
[4f13e19]678}
679
[b08fb02]680errno_t async_req_3_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
681 sysarg_t arg2, sysarg_t arg3, sysarg_t *r1)
[4f13e19]682{
[b08fb02]683 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, NULL, NULL,
684 NULL, NULL);
[4f13e19]685}
686
[b08fb02]687errno_t async_req_3_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
688 sysarg_t arg2, sysarg_t arg3, sysarg_t *r1, sysarg_t *r2)
[4f13e19]689{
[b08fb02]690 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, NULL,
691 NULL, NULL);
[4f13e19]692}
693
[b08fb02]694errno_t async_req_3_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
695 sysarg_t arg2, sysarg_t arg3, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3)
[4f13e19]696{
[b08fb02]697 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, NULL,
698 NULL);
[4f13e19]699}
700
[b08fb02]701errno_t async_req_3_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
702 sysarg_t arg2, sysarg_t arg3, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3,
703 sysarg_t *r4)
[4f13e19]704{
[b08fb02]705 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, r4,
706 NULL);
[4f13e19]707}
708
[b08fb02]709errno_t async_req_3_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
710 sysarg_t arg2, sysarg_t arg3, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3,
711 sysarg_t *r4, sysarg_t *r5)
[4f13e19]712{
[b08fb02]713 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, r4,
714 r5);
[4f13e19]715}
716
[b08fb02]717errno_t async_req_4_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
718 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
[4f13e19]719{
[b08fb02]720 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
721 NULL, NULL, NULL);
[4f13e19]722}
723
[b08fb02]724errno_t async_req_4_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
725 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1)
[4f13e19]726{
[b08fb02]727 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, NULL,
728 NULL, NULL, NULL);
[4f13e19]729}
730
[b08fb02]731errno_t async_req_4_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
732 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2)
[4f13e19]733{
[b08fb02]734 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, NULL,
735 NULL, NULL);
[4f13e19]736}
737
[b08fb02]738errno_t async_req_4_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
739 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
740 sysarg_t *r3)
[4f13e19]741{
[b08fb02]742 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3,
743 NULL, NULL);
[4f13e19]744}
745
[b08fb02]746errno_t async_req_4_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
747 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
748 sysarg_t *r3, sysarg_t *r4)
[4f13e19]749{
[b08fb02]750 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3,
751 r4, NULL);
[4f13e19]752}
753
[b08fb02]754errno_t async_req_4_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
755 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
756 sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[4f13e19]757{
[b08fb02]758 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3,
759 r4, r5);
[4f13e19]760}
761
[b08fb02]762errno_t async_req_5_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
763 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
[4f13e19]764{
[b08fb02]765 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
766 NULL, NULL, NULL, NULL);
[4f13e19]767}
768
[b08fb02]769errno_t async_req_5_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
770 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1)
[4f13e19]771{
[b08fb02]772 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1,
773 NULL, NULL, NULL, NULL);
[4f13e19]774}
775
[b08fb02]776errno_t async_req_5_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
777 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
778 sysarg_t *r2)
[4f13e19]779{
[b08fb02]780 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2,
781 NULL, NULL, NULL);
[4f13e19]782}
783
[b08fb02]784errno_t async_req_5_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
785 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
786 sysarg_t *r2, sysarg_t *r3)
[4f13e19]787{
[b08fb02]788 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2,
789 r3, NULL, NULL);
[4f13e19]790}
791
[b08fb02]792errno_t async_req_5_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
793 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
794 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4)
[4f13e19]795{
[b08fb02]796 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2,
797 r3, r4, NULL);
[4f13e19]798}
799
[b08fb02]800errno_t async_req_5_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
801 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
802 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
[4f13e19]803{
[b08fb02]804 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2,
805 r3, r4, r5);
[4f13e19]806}
807
[49a796f1]808void async_msg_0(async_exch_t *exch, sysarg_t imethod)
809{
810 if (exch != NULL)
[d054ad3]811 ipc_call_async_0(exch->phone, imethod, NULL);
[49a796f1]812}
813
814void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
815{
816 if (exch != NULL)
[d054ad3]817 ipc_call_async_1(exch->phone, imethod, arg1, NULL);
[49a796f1]818}
819
820void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
821 sysarg_t arg2)
822{
823 if (exch != NULL)
[d054ad3]824 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL);
[49a796f1]825}
826
827void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
828 sysarg_t arg2, sysarg_t arg3)
829{
830 if (exch != NULL)
[d054ad3]831 ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL);
[49a796f1]832}
833
834void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
835 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
836{
837 if (exch != NULL)
838 ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
[d054ad3]839 NULL);
[49a796f1]840}
841
842void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
843 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
844{
845 if (exch != NULL)
846 ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
[d054ad3]847 arg5, NULL);
[49a796f1]848}
849
850static errno_t async_connect_me_to_internal(cap_phone_handle_t phone,
[914c693]851 iface_t iface, sysarg_t arg2, sysarg_t arg3, sysarg_t flags,
[49a796f1]852 cap_phone_handle_t *out_phone)
853{
854 ipc_call_t result;
855
856 // XXX: Workaround for GCC's inability to infer association between
857 // rc == EOK and *out_phone being assigned.
858 *out_phone = CAP_NIL;
859
860 amsg_t *msg = amsg_create();
861 if (!msg)
862 return ENOENT;
863
864 msg->dataptr = &result;
865
[d054ad3]866 errno_t rc = ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO,
867 (sysarg_t) iface, arg2, arg3, flags, msg);
868 if (rc != EOK) {
869 msg->retval = rc;
870 msg->done = true;
871 }
[49a796f1]872
873 async_wait_for((aid_t) msg, &rc);
874
875 if (rc != EOK)
876 return rc;
877
[fafb8e5]878 *out_phone = (cap_phone_handle_t) ipc_get_arg5(&result);
[49a796f1]879 return EOK;
880}
881
882/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
883 *
884 * Ask through phone for a new connection to some service and block until
885 * success.
886 *
887 * @param exch Exchange for sending the message.
888 * @param iface Connection interface.
889 * @param arg2 User defined argument.
890 * @param arg3 User defined argument.
[01900b6]891 * @param rc Placeholder for return code. Unused if NULL.
[49a796f1]892 *
893 * @return New session on success or NULL on error.
894 *
895 */
[914c693]896async_sess_t *async_connect_me_to(async_exch_t *exch, iface_t iface,
[01900b6]897 sysarg_t arg2, sysarg_t arg3, errno_t *rc)
[49a796f1]898{
899 if (exch == NULL) {
[01900b6]900 if (rc != NULL)
901 *rc = ENOENT;
902
[49a796f1]903 return NULL;
904 }
905
[498ced1]906 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
[49a796f1]907 if (sess == NULL) {
[01900b6]908 if (rc != NULL)
909 *rc = ENOMEM;
910
[49a796f1]911 return NULL;
912 }
913
914 cap_phone_handle_t phone;
[01900b6]915 errno_t ret = async_connect_me_to_internal(exch->phone, iface, arg2,
[49a796f1]916 arg3, 0, &phone);
[01900b6]917 if (ret != EOK) {
918 if (rc != NULL)
919 *rc = ret;
920
[49a796f1]921 free(sess);
922 return NULL;
923 }
924
925 sess->iface = iface;
926 sess->phone = phone;
927 sess->arg1 = iface;
928 sess->arg2 = arg2;
929 sess->arg3 = arg3;
930
931 fibril_mutex_initialize(&sess->remote_state_mtx);
932 list_initialize(&sess->exch_list);
933 fibril_mutex_initialize(&sess->mutex);
934
935 return sess;
936}
937
938/** Set arguments for new connections.
939 *
940 * FIXME This is an ugly hack to work around the problem that parallel
941 * exchanges are implemented using parallel connections. When we create
942 * a callback session, the framework does not know arguments for the new
943 * connections.
944 *
945 * The proper solution seems to be to implement parallel exchanges using
946 * tagging.
[efa3136]947 *
[49a796f1]948 */
[914c693]949void async_sess_args_set(async_sess_t *sess, iface_t iface, sysarg_t arg2,
[49a796f1]950 sysarg_t arg3)
951{
[914c693]952 sess->arg1 = iface;
[49a796f1]953 sess->arg2 = arg2;
954 sess->arg3 = arg3;
955}
956
957/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
958 *
959 * Ask through phone for a new connection to some service and block until
960 * success.
961 *
962 * @param exch Exchange for sending the message.
963 * @param iface Connection interface.
964 * @param arg2 User defined argument.
965 * @param arg3 User defined argument.
[01900b6]966 * @param rc Placeholder for return code. Unused if NULL.
[49a796f1]967 *
968 * @return New session on success or NULL on error.
969 *
970 */
[914c693]971async_sess_t *async_connect_me_to_blocking(async_exch_t *exch, iface_t iface,
[01900b6]972 sysarg_t arg2, sysarg_t arg3, errno_t *rc)
[49a796f1]973{
974 if (exch == NULL) {
[01900b6]975 if (rc != NULL)
976 *rc = ENOENT;
977
[49a796f1]978 return NULL;
979 }
980
[498ced1]981 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
[49a796f1]982 if (sess == NULL) {
[01900b6]983 if (rc != NULL)
984 *rc = ENOMEM;
985
[49a796f1]986 return NULL;
987 }
988
989 cap_phone_handle_t phone;
[01900b6]990 errno_t ret = async_connect_me_to_internal(exch->phone, iface, arg2,
[49a796f1]991 arg3, IPC_FLAG_BLOCKING, &phone);
[01900b6]992 if (ret != EOK) {
993 if (rc != NULL)
994 *rc = ret;
995
[49a796f1]996 free(sess);
997 return NULL;
998 }
999
1000 sess->iface = iface;
1001 sess->phone = phone;
1002 sess->arg1 = iface;
1003 sess->arg2 = arg2;
1004 sess->arg3 = arg3;
1005
1006 fibril_mutex_initialize(&sess->remote_state_mtx);
1007 list_initialize(&sess->exch_list);
1008 fibril_mutex_initialize(&sess->mutex);
1009
1010 return sess;
1011}
1012
1013/** Connect to a task specified by id.
[01900b6]1014 *
1015 * @param id Task to which to connect.
1016 * @param rc Placeholder for return code. Unused if NULL.
1017 *
1018 * @return New session on success or NULL on error.
[49a796f1]1019 *
1020 */
[01900b6]1021async_sess_t *async_connect_kbox(task_id_t id, errno_t *rc)
[49a796f1]1022{
[498ced1]1023 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
[49a796f1]1024 if (sess == NULL) {
[01900b6]1025 if (rc != NULL)
1026 *rc = ENOMEM;
1027
[49a796f1]1028 return NULL;
1029 }
1030
1031 cap_phone_handle_t phone;
[01900b6]1032 errno_t ret = ipc_connect_kbox(id, &phone);
1033 if (ret != EOK) {
1034 if (rc != NULL)
1035 *rc = ret;
1036
[49a796f1]1037 free(sess);
1038 return NULL;
1039 }
1040
1041 sess->iface = 0;
1042 sess->mgmt = EXCHANGE_ATOMIC;
1043 sess->phone = phone;
1044
1045 fibril_mutex_initialize(&sess->remote_state_mtx);
1046 list_initialize(&sess->exch_list);
1047 fibril_mutex_initialize(&sess->mutex);
1048
1049 return sess;
1050}
1051
1052static errno_t async_hangup_internal(cap_phone_handle_t phone)
1053{
1054 return ipc_hangup(phone);
1055}
1056
1057/** Wrapper for ipc_hangup.
1058 *
1059 * @param sess Session to hung up.
1060 *
1061 * @return Zero on success or an error code.
1062 *
1063 */
1064errno_t async_hangup(async_sess_t *sess)
1065{
1066 async_exch_t *exch;
1067
1068 assert(sess);
1069
1070 fibril_mutex_lock(&async_sess_mutex);
1071
[be34d6f]1072 if (sess->exchanges > 0) {
1073 fibril_mutex_unlock(&async_sess_mutex);
1074 return EBUSY;
1075 }
[498ced1]1076
[49a796f1]1077 errno_t rc = async_hangup_internal(sess->phone);
1078
1079 while (!list_empty(&sess->exch_list)) {
1080 exch = (async_exch_t *)
1081 list_get_instance(list_first(&sess->exch_list),
1082 async_exch_t, sess_link);
1083
1084 list_remove(&exch->sess_link);
1085 list_remove(&exch->global_link);
1086 async_hangup_internal(exch->phone);
1087 free(exch);
1088 }
1089
1090 free(sess);
1091
1092 fibril_mutex_unlock(&async_sess_mutex);
1093
1094 return rc;
1095}
1096
1097/** Start new exchange in a session.
1098 *
1099 * @param session Session.
1100 *
1101 * @return New exchange or NULL on error.
1102 *
1103 */
1104async_exch_t *async_exchange_begin(async_sess_t *sess)
1105{
1106 if (sess == NULL)
1107 return NULL;
1108
1109 exch_mgmt_t mgmt = sess->mgmt;
1110 if (sess->iface != 0)
1111 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
1112
1113 async_exch_t *exch = NULL;
1114
1115 fibril_mutex_lock(&async_sess_mutex);
1116
1117 if (!list_empty(&sess->exch_list)) {
1118 /*
1119 * There are inactive exchanges in the session.
1120 */
1121 exch = (async_exch_t *)
1122 list_get_instance(list_first(&sess->exch_list),
1123 async_exch_t, sess_link);
1124
1125 list_remove(&exch->sess_link);
1126 list_remove(&exch->global_link);
1127 } else {
1128 /*
1129 * There are no available exchanges in the session.
1130 */
1131
1132 if ((mgmt == EXCHANGE_ATOMIC) ||
1133 (mgmt == EXCHANGE_SERIALIZE)) {
1134 exch = (async_exch_t *) malloc(sizeof(async_exch_t));
1135 if (exch != NULL) {
1136 link_initialize(&exch->sess_link);
1137 link_initialize(&exch->global_link);
1138 exch->sess = sess;
1139 exch->phone = sess->phone;
1140 }
1141 } else if (mgmt == EXCHANGE_PARALLEL) {
1142 cap_phone_handle_t phone;
1143 errno_t rc;
1144
1145 retry:
1146 /*
1147 * Make a one-time attempt to connect a new data phone.
1148 */
1149 rc = async_connect_me_to_internal(sess->phone, sess->arg1,
1150 sess->arg2, sess->arg3, 0, &phone);
1151 if (rc == EOK) {
1152 exch = (async_exch_t *) malloc(sizeof(async_exch_t));
1153 if (exch != NULL) {
1154 link_initialize(&exch->sess_link);
1155 link_initialize(&exch->global_link);
1156 exch->sess = sess;
1157 exch->phone = phone;
1158 } else
1159 async_hangup_internal(phone);
1160 } else if (!list_empty(&inactive_exch_list)) {
1161 /*
1162 * We did not manage to connect a new phone. But we
1163 * can try to close some of the currently inactive
1164 * connections in other sessions and try again.
1165 */
1166 exch = (async_exch_t *)
1167 list_get_instance(list_first(&inactive_exch_list),
1168 async_exch_t, global_link);
1169
1170 list_remove(&exch->sess_link);
1171 list_remove(&exch->global_link);
1172 async_hangup_internal(exch->phone);
1173 free(exch);
1174 goto retry;
1175 } else {
1176 /*
1177 * Wait for a phone to become available.
1178 */
1179 fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
1180 goto retry;
1181 }
1182 }
1183 }
1184
[498ced1]1185 if (exch != NULL)
1186 sess->exchanges++;
[49a796f1]1187
[498ced1]1188 fibril_mutex_unlock(&async_sess_mutex);
[49a796f1]1189
[498ced1]1190 if (exch != NULL && mgmt == EXCHANGE_SERIALIZE)
1191 fibril_mutex_lock(&sess->mutex);
[49a796f1]1192
1193 return exch;
1194}
1195
1196/** Finish an exchange.
1197 *
1198 * @param exch Exchange to finish.
1199 *
1200 */
1201void async_exchange_end(async_exch_t *exch)
1202{
1203 if (exch == NULL)
1204 return;
1205
1206 async_sess_t *sess = exch->sess;
1207 assert(sess != NULL);
1208
1209 exch_mgmt_t mgmt = sess->mgmt;
1210 if (sess->iface != 0)
1211 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
1212
1213 if (mgmt == EXCHANGE_SERIALIZE)
1214 fibril_mutex_unlock(&sess->mutex);
1215
1216 fibril_mutex_lock(&async_sess_mutex);
1217
[498ced1]1218 sess->exchanges--;
1219
[49a796f1]1220 list_append(&exch->sess_link, &sess->exch_list);
1221 list_append(&exch->global_link, &inactive_exch_list);
1222 fibril_condvar_signal(&avail_phone_cv);
1223
1224 fibril_mutex_unlock(&async_sess_mutex);
1225}
1226
1227/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
1228 *
1229 * @param exch Exchange for sending the message.
1230 * @param size Size of the destination address space area.
1231 * @param arg User defined argument.
1232 * @param flags Storage for the received flags. Can be NULL.
1233 * @param dst Address of the storage for the destination address space area
1234 * base address. Cannot be NULL.
1235 *
1236 * @return Zero on success or an error code from errno.h.
1237 *
1238 */
[4f13e19]1239static errno_t async_share_in_start(async_exch_t *exch, size_t size,
1240 sysarg_t arg, unsigned int *flags, void **dst)
[49a796f1]1241{
1242 if (exch == NULL)
1243 return ENOENT;
1244
1245 sysarg_t _flags = 0;
1246 sysarg_t _dst = (sysarg_t) -1;
[f2c8f55]1247 errno_t res = async_req_3_5(exch, IPC_M_SHARE_IN, (sysarg_t) size,
1248 (sysarg_t) __progsymbols.end, arg, NULL, &_flags, NULL, NULL,
1249 &_dst);
[49a796f1]1250
1251 if (flags)
1252 *flags = (unsigned int) _flags;
1253
1254 *dst = (void *) _dst;
1255 return res;
1256}
1257
[4f13e19]1258errno_t async_share_in_start_0_0(async_exch_t *exch, size_t size, void **dst)
1259{
1260 return async_share_in_start(exch, size, 0, NULL, dst);
1261}
1262
1263errno_t async_share_in_start_0_1(async_exch_t *exch, size_t size,
1264 unsigned int *flags, void **dst)
1265{
1266 return async_share_in_start(exch, size, 0, flags, dst);
1267}
1268
1269errno_t async_share_in_start_1_0(async_exch_t *exch, size_t size, sysarg_t arg,
1270 void **dst)
1271{
1272 return async_share_in_start(exch, size, arg, NULL, dst);
1273}
1274
1275errno_t async_share_in_start_1_1(async_exch_t *exch, size_t size, sysarg_t arg,
1276 unsigned int *flags, void **dst)
1277{
1278 return async_share_in_start(exch, size, arg, flags, dst);
1279}
1280
[49a796f1]1281/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
1282 *
1283 * @param exch Exchange for sending the message.
1284 * @param src Source address space area base address.
1285 * @param flags Flags to be used for sharing. Bits can be only cleared.
1286 *
1287 * @return Zero on success or an error code from errno.h.
1288 *
1289 */
1290errno_t async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
1291{
1292 if (exch == NULL)
1293 return ENOENT;
1294
1295 return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
1296 (sysarg_t) flags);
1297}
1298
1299/** Start IPC_M_DATA_READ using the async framework.
1300 *
1301 * @param exch Exchange for sending the message.
1302 * @param dst Address of the beginning of the destination buffer.
1303 * @param size Size of the destination buffer (in bytes).
1304 * @param dataptr Storage of call data (arg 2 holds actual data size).
1305 *
1306 * @return Hash of the sent message or 0 on error.
1307 *
1308 */
1309aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
1310 ipc_call_t *dataptr)
1311{
1312 return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
1313 (sysarg_t) size, dataptr);
1314}
1315
1316/** Wrapper for IPC_M_DATA_READ calls using the async framework.
1317 *
1318 * @param exch Exchange for sending the message.
1319 * @param dst Address of the beginning of the destination buffer.
1320 * @param size Size of the destination buffer.
1321 *
1322 * @return Zero on success or an error code from errno.h.
1323 *
1324 */
1325errno_t async_data_read_start(async_exch_t *exch, void *dst, size_t size)
1326{
1327 if (exch == NULL)
1328 return ENOENT;
1329
1330 return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
1331 (sysarg_t) size);
1332}
1333
1334/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
1335 *
1336 * @param exch Exchange for sending the message.
1337 * @param src Address of the beginning of the source buffer.
1338 * @param size Size of the source buffer.
1339 *
1340 * @return Zero on success or an error code from errno.h.
1341 *
1342 */
1343errno_t async_data_write_start(async_exch_t *exch, const void *src, size_t size)
1344{
1345 if (exch == NULL)
1346 return ENOENT;
1347
1348 return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
1349 (sysarg_t) size);
1350}
1351
1352errno_t async_state_change_start(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
1353 sysarg_t arg3, async_exch_t *other_exch)
1354{
1355 return async_req_5_0(exch, IPC_M_STATE_CHANGE_AUTHORIZE,
[bb97118]1356 arg1, arg2, arg3, 0, cap_handle_raw(other_exch->phone));
[49a796f1]1357}
1358
1359/** Lock and get session remote state
1360 *
1361 * Lock and get the local replica of the remote state
1362 * in stateful sessions. The call should be paired
1363 * with async_remote_state_release*().
1364 *
1365 * @param[in] sess Stateful session.
1366 *
1367 * @return Local replica of the remote state.
1368 *
1369 */
1370void *async_remote_state_acquire(async_sess_t *sess)
1371{
1372 fibril_mutex_lock(&sess->remote_state_mtx);
1373 return sess->remote_state_data;
1374}
1375
1376/** Update the session remote state
1377 *
1378 * Update the local replica of the remote state
1379 * in stateful sessions. The remote state must
1380 * be already locked.
1381 *
1382 * @param[in] sess Stateful session.
1383 * @param[in] state New local replica of the remote state.
1384 *
1385 */
1386void async_remote_state_update(async_sess_t *sess, void *state)
1387{
1388 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1389 sess->remote_state_data = state;
1390}
1391
1392/** Release the session remote state
1393 *
1394 * Unlock the local replica of the remote state
1395 * in stateful sessions.
1396 *
1397 * @param[in] sess Stateful session.
1398 *
1399 */
1400void async_remote_state_release(async_sess_t *sess)
1401{
1402 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1403
1404 fibril_mutex_unlock(&sess->remote_state_mtx);
1405}
1406
1407/** Release the session remote state and end an exchange
1408 *
1409 * Unlock the local replica of the remote state
1410 * in stateful sessions. This is convenience function
1411 * which gets the session pointer from the exchange
1412 * and also ends the exchange.
1413 *
1414 * @param[in] exch Stateful session's exchange.
1415 *
1416 */
1417void async_remote_state_release_exchange(async_exch_t *exch)
1418{
1419 if (exch == NULL)
1420 return;
1421
1422 async_sess_t *sess = exch->sess;
1423 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1424
1425 async_exchange_end(exch);
1426 fibril_mutex_unlock(&sess->remote_state_mtx);
1427}
1428
1429void *async_as_area_create(void *base, size_t size, unsigned int flags,
1430 async_sess_t *pager, sysarg_t id1, sysarg_t id2, sysarg_t id3)
1431{
1432 as_area_pager_info_t pager_info = {
1433 .pager = pager->phone,
1434 .id1 = id1,
1435 .id2 = id2,
1436 .id3 = id3
1437 };
1438 return as_area_create(base, size, flags, &pager_info);
1439}
1440
1441/** @}
1442 */
Note: See TracBrowser for help on using the repository browser.