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

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

sysman: Move task retval and waiting logic to taskman (partially)

  • two important sessions: NS and taskman
  • depending on boot task vs spawned task those sessions are initiated differently

Conflicts:

uspace/lib/c/generic/async.c
uspace/lib/c/generic/libc.c
uspace/lib/c/generic/task.c
uspace/lib/c/include/ipc/ns.h
uspace/lib/c/include/task.h
uspace/lib/posix/source/sys/wait.c
uspace/srv/loader/main.c
uspace/srv/ns/ns.c

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