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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 698ce34c was 698ce34c, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Async_hangup being called with async exchanges should be assertion failure

If this happens, there is a race between async_hangup() (which frees
the session) and using the session.

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