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

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

Correcting failure from previous merge

The commits from Michal Koutný from the branch system-daemon
where built on a old version of Helenos. Because of this
many types and API functions have changed. This commit
upgrades the merge code

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