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

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

Create taskman server (extracts task-related operations from naming service)

  • Exploits initial phones connected to spawn parent instead of NS.
  • session_ns changed to session_primary (setup during taskman-loader handshake).
  • Task creation moved from NS to taskman (no clonable services anymore).
  • Other task-related operations implementation is to come (task_retval is temporarily dummy).
  • Async framework: implicit connections — create fibrils for calls that arrived through initial phone.

Conflicts:

abi/include/abi/ipc/methods.h
boot/Makefile.common
uspace/Makefile
uspace/app/trace/ipcp.c
uspace/lib/c/generic/async.c
uspace/lib/c/generic/libc.c
uspace/lib/c/generic/loader.c
uspace/lib/c/generic/ns.c
uspace/lib/c/generic/private/async.h
uspace/lib/c/generic/private/ns.h
uspace/lib/c/generic/task.c
uspace/lib/c/include/async.h
uspace/lib/c/include/ipc/services.h
uspace/lib/c/include/ipc/taskman.h
uspace/lib/c/include/loader/pcb.h
uspace/lib/c/include/ns.h
uspace/srv/loader/main.c
uspace/srv/ns/clonable.c
uspace/srv/ns/ns.c

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