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

Last change on this file since 66b1075 was 16d748ee, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Removing implicit handler from async/server and taskman.
Correcting taskman methods and it's fallback handler
Simplifying connecting to taskman

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