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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4805495 was 4805495, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Make sure libc and abi header guards are reserved identifiers

It's only needed for a small subset that end up included from standard
headers, but for consistency this changes all of them.

  • Property mode set to 100644
File size: 36.4 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#include "../private/ns.h"
102#undef _LIBC_ASYNC_C_
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>
112#include <time.h>
113#include <barrier.h>
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"
122#include "../private/fibril.h"
123
124static fibril_rmutex_t message_mutex;
125
126/** Naming service session */
127async_sess_t session_ns;
128
129/** Message data */
130typedef struct {
131 fibril_event_t received;
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{
147 return calloc(1, sizeof(amsg_t));
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{
175 if (fibril_rmutex_initialize(&message_mutex) != EOK)
176 abort();
177
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);
190 session_ns.exchanges = 0;
191}
192
193void __async_client_fini(void)
194{
195 fibril_rmutex_destroy(&message_mutex);
196}
197
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 */
210void async_reply_received(ipc_call_t *data)
211{
212 amsg_t *msg = (amsg_t *) data->answer_label;
213 if (!msg)
214 return;
215
216 fibril_rmutex_lock(&message_mutex);
217
218 msg->retval = IPC_GET_RETVAL(*data);
219
220 /* Copy data inside lock, just in case the call was detached */
221 if ((msg->dataptr) && (data))
222 *msg->dataptr = *data;
223
224 msg->done = true;
225
226 if (msg->forget) {
227 amsg_destroy(msg);
228 } else {
229 fibril_notify(&msg->received);
230 }
231
232 fibril_rmutex_unlock(&message_mutex);
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 */
251static aid_t async_send_fast(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
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
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 }
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 */
291static aid_t async_send_slow(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
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
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 }
310
311 return (aid_t) msg;
312}
313
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
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{
360 if (amsgid == 0) {
361 if (retval)
362 *retval = ENOMEM;
363 return;
364 }
365
366 amsg_t *msg = (amsg_t *) amsgid;
367 fibril_wait_for(&msg->received);
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 */
389errno_t async_wait_timeout(aid_t amsgid, errno_t *retval, usec_t timeout)
390{
391 if (amsgid == 0) {
392 if (retval)
393 *retval = ENOMEM;
394 return EOK;
395 }
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
406 struct timespec expires;
407 getuptime(&expires);
408 ts_add_diff(&expires, USEC2NSEC(timeout));
409
410 errno_t rc = fibril_wait_timeout(&msg->received, &expires);
411 if (rc != EOK)
412 return rc;
413
414 if (retval)
415 *retval = msg->retval;
416
417 amsg_destroy(msg);
418
419 return EOK;
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{
432 if (amsgid == 0)
433 return;
434
435 amsg_t *msg = (amsg_t *) amsgid;
436
437 assert(!msg->forget);
438
439 fibril_rmutex_lock(&message_mutex);
440
441 if (msg->done) {
442 amsg_destroy(msg);
443 } else {
444 msg->dataptr = NULL;
445 msg->forget = true;
446 }
447
448 fibril_rmutex_unlock(&message_mutex);
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 */
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)
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)
488 *r1 = IPC_GET_ARG1(result);
489
490 if (r2)
491 *r2 = IPC_GET_ARG2(result);
492
493 if (r3)
494 *r3 = IPC_GET_ARG3(result);
495
496 if (r4)
497 *r4 = IPC_GET_ARG4(result);
498
499 if (r5)
500 *r5 = IPC_GET_ARG5(result);
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 */
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)
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)
540 *r1 = IPC_GET_ARG1(result);
541
542 if (r2)
543 *r2 = IPC_GET_ARG2(result);
544
545 if (r3)
546 *r3 = IPC_GET_ARG3(result);
547
548 if (r4)
549 *r4 = IPC_GET_ARG4(result);
550
551 if (r5)
552 *r5 = IPC_GET_ARG5(result);
553
554 return rc;
555}
556
557errno_t async_req_0_0(async_exch_t *exch, sysarg_t imethod)
558{
559 return async_req_fast(exch, imethod, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
560}
561
562errno_t async_req_0_1(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1)
563{
564 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, NULL, NULL, NULL, NULL);
565}
566
567errno_t async_req_0_2(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1, sysarg_t *r2)
568{
569 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, NULL, NULL, NULL);
570}
571
572errno_t async_req_0_3(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3)
573{
574 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, NULL, NULL);
575}
576
577errno_t async_req_0_4(async_exch_t *exch, sysarg_t imethod, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3, sysarg_t *r4)
578{
579 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, r4, NULL);
580}
581
582errno_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)
583{
584 return async_req_fast(exch, imethod, 0, 0, 0, 0, r1, r2, r3, r4, r5);
585}
586
587errno_t async_req_1_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
588{
589 return async_req_fast(exch, imethod, arg1, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
590}
591
592errno_t async_req_1_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t *r1)
593{
594 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, NULL, NULL, NULL, NULL);
595}
596
597errno_t async_req_1_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t *r1, sysarg_t *r2)
598{
599 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, NULL, NULL, NULL);
600}
601
602errno_t async_req_1_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t *r1, sysarg_t *r2, sysarg_t *r3)
603{
604 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, NULL, NULL);
605}
606
607errno_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)
608{
609 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, r4, NULL);
610}
611
612errno_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)
613{
614 return async_req_fast(exch, imethod, arg1, 0, 0, 0, r1, r2, r3, r4, r5);
615}
616
617errno_t async_req_2_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
618{
619 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, NULL, NULL, NULL, NULL, NULL);
620}
621
622errno_t async_req_2_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t *r1)
623{
624 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, NULL, NULL, NULL, NULL);
625}
626
627errno_t async_req_2_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t *r1, sysarg_t *r2)
628{
629 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, NULL, NULL, NULL);
630}
631
632errno_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)
633{
634 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, NULL, NULL);
635}
636
637errno_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)
638{
639 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, r4, NULL);
640}
641
642errno_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)
643{
644 return async_req_fast(exch, imethod, arg1, arg2, 0, 0, r1, r2, r3, r4, r5);
645}
646
647errno_t async_req_3_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
648{
649 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, NULL, NULL, NULL, NULL, NULL);
650}
651
652errno_t async_req_3_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t *r1)
653{
654 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, NULL, NULL, NULL, NULL);
655}
656
657errno_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)
658{
659 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, NULL, NULL, NULL);
660}
661
662errno_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)
663{
664 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, NULL, NULL);
665}
666
667errno_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)
668{
669 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, r4, NULL);
670}
671
672errno_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)
673{
674 return async_req_fast(exch, imethod, arg1, arg2, arg3, 0, r1, r2, r3, r4, r5);
675}
676
677errno_t async_req_4_0(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
678{
679 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, NULL, NULL, NULL, NULL, NULL);
680}
681
682errno_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)
683{
684 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, NULL, NULL, NULL, NULL);
685}
686
687errno_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)
688{
689 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, NULL, NULL, NULL);
690}
691
692errno_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)
693{
694 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3, NULL, NULL);
695}
696
697errno_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)
698{
699 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3, r4, NULL);
700}
701
702errno_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)
703{
704 return async_req_fast(exch, imethod, arg1, arg2, arg3, arg4, r1, r2, r3, r4, r5);
705}
706
707errno_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)
708{
709 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, NULL, NULL, NULL, NULL, NULL);
710}
711
712errno_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)
713{
714 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, NULL, NULL, NULL, NULL);
715}
716
717errno_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)
718{
719 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2, NULL, NULL, NULL);
720}
721
722errno_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)
723{
724 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2, r3, NULL, NULL);
725}
726
727errno_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)
728{
729 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2, r3, r4, NULL);
730}
731
732errno_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)
733{
734 return async_req_slow(exch, imethod, arg1, arg2, arg3, arg4, arg5, r1, r2, r3, r4, r5);
735}
736
737void async_msg_0(async_exch_t *exch, sysarg_t imethod)
738{
739 if (exch != NULL)
740 ipc_call_async_0(exch->phone, imethod, NULL);
741}
742
743void async_msg_1(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1)
744{
745 if (exch != NULL)
746 ipc_call_async_1(exch->phone, imethod, arg1, NULL);
747}
748
749void async_msg_2(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
750 sysarg_t arg2)
751{
752 if (exch != NULL)
753 ipc_call_async_2(exch->phone, imethod, arg1, arg2, NULL);
754}
755
756void async_msg_3(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
757 sysarg_t arg2, sysarg_t arg3)
758{
759 if (exch != NULL)
760 ipc_call_async_3(exch->phone, imethod, arg1, arg2, arg3, NULL);
761}
762
763void async_msg_4(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
764 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
765{
766 if (exch != NULL)
767 ipc_call_async_4(exch->phone, imethod, arg1, arg2, arg3, arg4,
768 NULL);
769}
770
771void async_msg_5(async_exch_t *exch, sysarg_t imethod, sysarg_t arg1,
772 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
773{
774 if (exch != NULL)
775 ipc_call_async_5(exch->phone, imethod, arg1, arg2, arg3, arg4,
776 arg5, NULL);
777}
778
779static errno_t async_connect_me_to_internal(cap_phone_handle_t phone,
780 iface_t iface, sysarg_t arg2, sysarg_t arg3, sysarg_t flags,
781 cap_phone_handle_t *out_phone)
782{
783 ipc_call_t result;
784
785 // XXX: Workaround for GCC's inability to infer association between
786 // rc == EOK and *out_phone being assigned.
787 *out_phone = CAP_NIL;
788
789 amsg_t *msg = amsg_create();
790 if (!msg)
791 return ENOENT;
792
793 msg->dataptr = &result;
794
795 errno_t rc = ipc_call_async_4(phone, IPC_M_CONNECT_ME_TO,
796 (sysarg_t) iface, arg2, arg3, flags, msg);
797 if (rc != EOK) {
798 msg->retval = rc;
799 msg->done = true;
800 }
801
802 async_wait_for((aid_t) msg, &rc);
803
804 if (rc != EOK)
805 return rc;
806
807 *out_phone = (cap_phone_handle_t) IPC_GET_ARG5(result);
808 return EOK;
809}
810
811/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
812 *
813 * Ask through phone for a new connection to some service and block until
814 * success.
815 *
816 * @param exch Exchange for sending the message.
817 * @param iface Connection interface.
818 * @param arg2 User defined argument.
819 * @param arg3 User defined argument.
820 *
821 * @return New session on success or NULL on error.
822 *
823 */
824async_sess_t *async_connect_me_to(async_exch_t *exch, iface_t iface,
825 sysarg_t arg2, sysarg_t arg3)
826{
827 if (exch == NULL) {
828 errno = ENOENT;
829 return NULL;
830 }
831
832 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
833 if (sess == NULL) {
834 errno = ENOMEM;
835 return NULL;
836 }
837
838 cap_phone_handle_t phone;
839 errno_t rc = async_connect_me_to_internal(exch->phone, iface, arg2,
840 arg3, 0, &phone);
841 if (rc != EOK) {
842 errno = rc;
843 free(sess);
844 return NULL;
845 }
846
847 sess->iface = iface;
848 sess->phone = phone;
849 sess->arg1 = iface;
850 sess->arg2 = arg2;
851 sess->arg3 = arg3;
852
853 fibril_mutex_initialize(&sess->remote_state_mtx);
854 list_initialize(&sess->exch_list);
855 fibril_mutex_initialize(&sess->mutex);
856
857 return sess;
858}
859
860/** Set arguments for new connections.
861 *
862 * FIXME This is an ugly hack to work around the problem that parallel
863 * exchanges are implemented using parallel connections. When we create
864 * a callback session, the framework does not know arguments for the new
865 * connections.
866 *
867 * The proper solution seems to be to implement parallel exchanges using
868 * tagging.
869 *
870 */
871void async_sess_args_set(async_sess_t *sess, iface_t iface, sysarg_t arg2,
872 sysarg_t arg3)
873{
874 sess->arg1 = iface;
875 sess->arg2 = arg2;
876 sess->arg3 = arg3;
877}
878
879/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
880 *
881 * Ask through phone for a new connection to some service and block until
882 * success.
883 *
884 * @param exch Exchange for sending the message.
885 * @param iface Connection interface.
886 * @param arg2 User defined argument.
887 * @param arg3 User defined argument.
888 *
889 * @return New session on success or NULL on error.
890 *
891 */
892async_sess_t *async_connect_me_to_blocking(async_exch_t *exch, iface_t iface,
893 sysarg_t arg2, sysarg_t arg3)
894{
895 if (exch == NULL) {
896 errno = ENOENT;
897 return NULL;
898 }
899
900 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
901 if (sess == NULL) {
902 errno = ENOMEM;
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 free(sess);
912 return NULL;
913 }
914
915 sess->iface = iface;
916 sess->phone = phone;
917 sess->arg1 = iface;
918 sess->arg2 = arg2;
919 sess->arg3 = arg3;
920
921 fibril_mutex_initialize(&sess->remote_state_mtx);
922 list_initialize(&sess->exch_list);
923 fibril_mutex_initialize(&sess->mutex);
924
925 return sess;
926}
927
928/** Connect to a task specified by id.
929 *
930 */
931async_sess_t *async_connect_kbox(task_id_t id)
932{
933 async_sess_t *sess = calloc(1, sizeof(async_sess_t));
934 if (sess == NULL) {
935 errno = ENOMEM;
936 return NULL;
937 }
938
939 cap_phone_handle_t phone;
940 errno_t rc = ipc_connect_kbox(id, &phone);
941 if (rc != EOK) {
942 errno = rc;
943 free(sess);
944 return NULL;
945 }
946
947 sess->iface = 0;
948 sess->mgmt = EXCHANGE_ATOMIC;
949 sess->phone = phone;
950
951 fibril_mutex_initialize(&sess->remote_state_mtx);
952 list_initialize(&sess->exch_list);
953 fibril_mutex_initialize(&sess->mutex);
954
955 return sess;
956}
957
958static errno_t async_hangup_internal(cap_phone_handle_t phone)
959{
960 return ipc_hangup(phone);
961}
962
963/** Wrapper for ipc_hangup.
964 *
965 * @param sess Session to hung up.
966 *
967 * @return Zero on success or an error code.
968 *
969 */
970errno_t async_hangup(async_sess_t *sess)
971{
972 async_exch_t *exch;
973
974 assert(sess);
975
976 fibril_mutex_lock(&async_sess_mutex);
977
978 if (sess->exchanges > 0) {
979 fibril_mutex_unlock(&async_sess_mutex);
980 return EBUSY;
981 }
982
983 errno_t rc = async_hangup_internal(sess->phone);
984
985 while (!list_empty(&sess->exch_list)) {
986 exch = (async_exch_t *)
987 list_get_instance(list_first(&sess->exch_list),
988 async_exch_t, sess_link);
989
990 list_remove(&exch->sess_link);
991 list_remove(&exch->global_link);
992 async_hangup_internal(exch->phone);
993 free(exch);
994 }
995
996 free(sess);
997
998 fibril_mutex_unlock(&async_sess_mutex);
999
1000 return rc;
1001}
1002
1003/** Start new exchange in a session.
1004 *
1005 * @param session Session.
1006 *
1007 * @return New exchange or NULL on error.
1008 *
1009 */
1010async_exch_t *async_exchange_begin(async_sess_t *sess)
1011{
1012 if (sess == NULL)
1013 return NULL;
1014
1015 exch_mgmt_t mgmt = sess->mgmt;
1016 if (sess->iface != 0)
1017 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
1018
1019 async_exch_t *exch = NULL;
1020
1021 fibril_mutex_lock(&async_sess_mutex);
1022
1023 if (!list_empty(&sess->exch_list)) {
1024 /*
1025 * There are inactive exchanges in the session.
1026 */
1027 exch = (async_exch_t *)
1028 list_get_instance(list_first(&sess->exch_list),
1029 async_exch_t, sess_link);
1030
1031 list_remove(&exch->sess_link);
1032 list_remove(&exch->global_link);
1033 } else {
1034 /*
1035 * There are no available exchanges in the session.
1036 */
1037
1038 if ((mgmt == EXCHANGE_ATOMIC) ||
1039 (mgmt == EXCHANGE_SERIALIZE)) {
1040 exch = (async_exch_t *) malloc(sizeof(async_exch_t));
1041 if (exch != NULL) {
1042 link_initialize(&exch->sess_link);
1043 link_initialize(&exch->global_link);
1044 exch->sess = sess;
1045 exch->phone = sess->phone;
1046 }
1047 } else if (mgmt == EXCHANGE_PARALLEL) {
1048 cap_phone_handle_t phone;
1049 errno_t rc;
1050
1051 retry:
1052 /*
1053 * Make a one-time attempt to connect a new data phone.
1054 */
1055 rc = async_connect_me_to_internal(sess->phone, sess->arg1,
1056 sess->arg2, sess->arg3, 0, &phone);
1057 if (rc == EOK) {
1058 exch = (async_exch_t *) malloc(sizeof(async_exch_t));
1059 if (exch != NULL) {
1060 link_initialize(&exch->sess_link);
1061 link_initialize(&exch->global_link);
1062 exch->sess = sess;
1063 exch->phone = phone;
1064 } else
1065 async_hangup_internal(phone);
1066 } else if (!list_empty(&inactive_exch_list)) {
1067 /*
1068 * We did not manage to connect a new phone. But we
1069 * can try to close some of the currently inactive
1070 * connections in other sessions and try again.
1071 */
1072 exch = (async_exch_t *)
1073 list_get_instance(list_first(&inactive_exch_list),
1074 async_exch_t, global_link);
1075
1076 list_remove(&exch->sess_link);
1077 list_remove(&exch->global_link);
1078 async_hangup_internal(exch->phone);
1079 free(exch);
1080 goto retry;
1081 } else {
1082 /*
1083 * Wait for a phone to become available.
1084 */
1085 fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
1086 goto retry;
1087 }
1088 }
1089 }
1090
1091 if (exch != NULL)
1092 sess->exchanges++;
1093
1094 fibril_mutex_unlock(&async_sess_mutex);
1095
1096 if (exch != NULL && mgmt == EXCHANGE_SERIALIZE)
1097 fibril_mutex_lock(&sess->mutex);
1098
1099 return exch;
1100}
1101
1102/** Finish an exchange.
1103 *
1104 * @param exch Exchange to finish.
1105 *
1106 */
1107void async_exchange_end(async_exch_t *exch)
1108{
1109 if (exch == NULL)
1110 return;
1111
1112 async_sess_t *sess = exch->sess;
1113 assert(sess != NULL);
1114
1115 exch_mgmt_t mgmt = sess->mgmt;
1116 if (sess->iface != 0)
1117 mgmt = sess->iface & IFACE_EXCHANGE_MASK;
1118
1119 if (mgmt == EXCHANGE_SERIALIZE)
1120 fibril_mutex_unlock(&sess->mutex);
1121
1122 fibril_mutex_lock(&async_sess_mutex);
1123
1124 sess->exchanges--;
1125
1126 list_append(&exch->sess_link, &sess->exch_list);
1127 list_append(&exch->global_link, &inactive_exch_list);
1128 fibril_condvar_signal(&avail_phone_cv);
1129
1130 fibril_mutex_unlock(&async_sess_mutex);
1131}
1132
1133/** Wrapper for IPC_M_SHARE_IN calls using the async framework.
1134 *
1135 * @param exch Exchange for sending the message.
1136 * @param size Size of the destination address space area.
1137 * @param arg User defined argument.
1138 * @param flags Storage for the received flags. Can be NULL.
1139 * @param dst Address of the storage for the destination address space area
1140 * base address. Cannot be NULL.
1141 *
1142 * @return Zero on success or an error code from errno.h.
1143 *
1144 */
1145static errno_t async_share_in_start(async_exch_t *exch, size_t size,
1146 sysarg_t arg, unsigned int *flags, void **dst)
1147{
1148 if (exch == NULL)
1149 return ENOENT;
1150
1151 sysarg_t _flags = 0;
1152 sysarg_t _dst = (sysarg_t) -1;
1153 errno_t res = async_req_3_5(exch, IPC_M_SHARE_IN, (sysarg_t) size,
1154 (sysarg_t) __progsymbols.end, arg, NULL, &_flags, NULL, NULL,
1155 &_dst);
1156
1157 if (flags)
1158 *flags = (unsigned int) _flags;
1159
1160 *dst = (void *) _dst;
1161 return res;
1162}
1163
1164errno_t async_share_in_start_0_0(async_exch_t *exch, size_t size, void **dst)
1165{
1166 return async_share_in_start(exch, size, 0, NULL, dst);
1167}
1168
1169errno_t async_share_in_start_0_1(async_exch_t *exch, size_t size,
1170 unsigned int *flags, void **dst)
1171{
1172 return async_share_in_start(exch, size, 0, flags, dst);
1173}
1174
1175errno_t async_share_in_start_1_0(async_exch_t *exch, size_t size, sysarg_t arg,
1176 void **dst)
1177{
1178 return async_share_in_start(exch, size, arg, NULL, dst);
1179}
1180
1181errno_t async_share_in_start_1_1(async_exch_t *exch, size_t size, sysarg_t arg,
1182 unsigned int *flags, void **dst)
1183{
1184 return async_share_in_start(exch, size, arg, flags, dst);
1185}
1186
1187/** Wrapper for IPC_M_SHARE_OUT calls using the async framework.
1188 *
1189 * @param exch Exchange for sending the message.
1190 * @param src Source address space area base address.
1191 * @param flags Flags to be used for sharing. Bits can be only cleared.
1192 *
1193 * @return Zero on success or an error code from errno.h.
1194 *
1195 */
1196errno_t async_share_out_start(async_exch_t *exch, void *src, unsigned int flags)
1197{
1198 if (exch == NULL)
1199 return ENOENT;
1200
1201 return async_req_3_0(exch, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
1202 (sysarg_t) flags);
1203}
1204
1205/** Start IPC_M_DATA_READ using the async framework.
1206 *
1207 * @param exch Exchange for sending the message.
1208 * @param dst Address of the beginning of the destination buffer.
1209 * @param size Size of the destination buffer (in bytes).
1210 * @param dataptr Storage of call data (arg 2 holds actual data size).
1211 *
1212 * @return Hash of the sent message or 0 on error.
1213 *
1214 */
1215aid_t async_data_read(async_exch_t *exch, void *dst, size_t size,
1216 ipc_call_t *dataptr)
1217{
1218 return async_send_2(exch, IPC_M_DATA_READ, (sysarg_t) dst,
1219 (sysarg_t) size, dataptr);
1220}
1221
1222/** Wrapper for IPC_M_DATA_READ calls using the async framework.
1223 *
1224 * @param exch Exchange for sending the message.
1225 * @param dst Address of the beginning of the destination buffer.
1226 * @param size Size of the destination buffer.
1227 *
1228 * @return Zero on success or an error code from errno.h.
1229 *
1230 */
1231errno_t async_data_read_start(async_exch_t *exch, void *dst, size_t size)
1232{
1233 if (exch == NULL)
1234 return ENOENT;
1235
1236 return async_req_2_0(exch, IPC_M_DATA_READ, (sysarg_t) dst,
1237 (sysarg_t) size);
1238}
1239
1240/** Wrapper for IPC_M_DATA_WRITE calls using the async framework.
1241 *
1242 * @param exch Exchange for sending the message.
1243 * @param src Address of the beginning of the source buffer.
1244 * @param size Size of the source buffer.
1245 *
1246 * @return Zero on success or an error code from errno.h.
1247 *
1248 */
1249errno_t async_data_write_start(async_exch_t *exch, const void *src, size_t size)
1250{
1251 if (exch == NULL)
1252 return ENOENT;
1253
1254 return async_req_2_0(exch, IPC_M_DATA_WRITE, (sysarg_t) src,
1255 (sysarg_t) size);
1256}
1257
1258errno_t async_state_change_start(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
1259 sysarg_t arg3, async_exch_t *other_exch)
1260{
1261 return async_req_5_0(exch, IPC_M_STATE_CHANGE_AUTHORIZE,
1262 arg1, arg2, arg3, 0, CAP_HANDLE_RAW(other_exch->phone));
1263}
1264
1265/** Lock and get session remote state
1266 *
1267 * Lock and get the local replica of the remote state
1268 * in stateful sessions. The call should be paired
1269 * with async_remote_state_release*().
1270 *
1271 * @param[in] sess Stateful session.
1272 *
1273 * @return Local replica of the remote state.
1274 *
1275 */
1276void *async_remote_state_acquire(async_sess_t *sess)
1277{
1278 fibril_mutex_lock(&sess->remote_state_mtx);
1279 return sess->remote_state_data;
1280}
1281
1282/** Update the session remote state
1283 *
1284 * Update the local replica of the remote state
1285 * in stateful sessions. The remote state must
1286 * be already locked.
1287 *
1288 * @param[in] sess Stateful session.
1289 * @param[in] state New local replica of the remote state.
1290 *
1291 */
1292void async_remote_state_update(async_sess_t *sess, void *state)
1293{
1294 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1295 sess->remote_state_data = state;
1296}
1297
1298/** Release the session remote state
1299 *
1300 * Unlock the local replica of the remote state
1301 * in stateful sessions.
1302 *
1303 * @param[in] sess Stateful session.
1304 *
1305 */
1306void async_remote_state_release(async_sess_t *sess)
1307{
1308 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1309
1310 fibril_mutex_unlock(&sess->remote_state_mtx);
1311}
1312
1313/** Release the session remote state and end an exchange
1314 *
1315 * Unlock the local replica of the remote state
1316 * in stateful sessions. This is convenience function
1317 * which gets the session pointer from the exchange
1318 * and also ends the exchange.
1319 *
1320 * @param[in] exch Stateful session's exchange.
1321 *
1322 */
1323void async_remote_state_release_exchange(async_exch_t *exch)
1324{
1325 if (exch == NULL)
1326 return;
1327
1328 async_sess_t *sess = exch->sess;
1329 assert(fibril_mutex_is_locked(&sess->remote_state_mtx));
1330
1331 async_exchange_end(exch);
1332 fibril_mutex_unlock(&sess->remote_state_mtx);
1333}
1334
1335void *async_as_area_create(void *base, size_t size, unsigned int flags,
1336 async_sess_t *pager, sysarg_t id1, sysarg_t id2, sysarg_t id3)
1337{
1338 as_area_pager_info_t pager_info = {
1339 .pager = pager->phone,
1340 .id1 = id1,
1341 .id2 = id2,
1342 .id3 = id3
1343 };
1344 return as_area_create(base, size, flags, &pager_info);
1345}
1346
1347/** @}
1348 */
Note: See TracBrowser for help on using the repository browser.