00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00089 #define LIBC_ASYNC_C_
00090 #include <ipc/ipc.h>
00091 #include <async.h>
00092 #undef LIBC_ASYNC_C_
00093
00094 #include <futex.h>
00095 #include <fibril.h>
00096 #include <stdio.h>
00097 #include <adt/hash_table.h>
00098 #include <adt/list.h>
00099 #include <assert.h>
00100 #include <errno.h>
00101 #include <sys/time.h>
00102 #include <arch/barrier.h>
00103 #include <bool.h>
00104 #include <stdlib.h>
00105 #include <malloc.h>
00106 #include "private/async.h"
00107
00108 atomic_t async_futex = FUTEX_INITIALIZER;
00109
00111 atomic_t threads_in_ipc_wait = { 0 };
00112
00113 typedef struct {
00114 awaiter_t wdata;
00115
00117 bool done;
00118
00120 ipc_call_t *dataptr;
00121
00122 sysarg_t retval;
00123 } amsg_t;
00124
00129 typedef struct {
00130 link_t link;
00131 ipc_callid_t callid;
00132 ipc_call_t call;
00133 } msg_t;
00134
00135 typedef struct {
00136 sysarg_t in_task_hash;
00137 link_t link;
00138 int refcnt;
00139 void *data;
00140 } client_t;
00141
00142 typedef struct {
00143 awaiter_t wdata;
00144
00146 link_t link;
00147
00149 sysarg_t in_task_hash;
00151 sysarg_t in_phone_hash;
00152
00154 client_t *client;
00155
00157 link_t msg_queue;
00158
00160 ipc_callid_t callid;
00162 ipc_call_t call;
00163
00165 ipc_callid_t close_callid;
00166
00168 void (*cfibril)(ipc_callid_t, ipc_call_t *);
00169 } connection_t;
00170
00172 static fibril_local connection_t *FIBRIL_connection;
00173
00174 static void *default_client_data_constructor(void)
00175 {
00176 return NULL;
00177 }
00178
00179 static void default_client_data_destructor(void *data)
00180 {
00181 }
00182
00183 static async_client_data_ctor_t async_client_data_create =
00184 default_client_data_constructor;
00185 static async_client_data_dtor_t async_client_data_destroy =
00186 default_client_data_destructor;
00187
00188 void async_set_client_data_constructor(async_client_data_ctor_t ctor)
00189 {
00190 async_client_data_create = ctor;
00191 }
00192
00193 void async_set_client_data_destructor(async_client_data_dtor_t dtor)
00194 {
00195 async_client_data_destroy = dtor;
00196 }
00197
00198 void *async_client_data_get(void)
00199 {
00200 assert(FIBRIL_connection);
00201 return FIBRIL_connection->client->data;
00202 }
00203
00212 static void default_client_connection(ipc_callid_t callid, ipc_call_t *call)
00213 {
00214 ipc_answer_0(callid, ENOENT);
00215 }
00216
00220 static async_client_conn_t client_connection = default_client_connection;
00221
00230 static void default_interrupt_received(ipc_callid_t callid, ipc_call_t *call)
00231 {
00232 }
00233
00238 static async_client_conn_t interrupt_received = default_interrupt_received;
00239
00240 static hash_table_t client_hash_table;
00241 static hash_table_t conn_hash_table;
00242 static LIST_INITIALIZE(timeout_list);
00243
00244 #define CLIENT_HASH_TABLE_BUCKETS 32
00245 #define CONN_HASH_TABLE_BUCKETS 32
00246
00247 static hash_index_t client_hash(unsigned long key[])
00248 {
00249 assert(key);
00250 return (((key[0]) >> 4) % CLIENT_HASH_TABLE_BUCKETS);
00251 }
00252
00253 static int client_compare(unsigned long key[], hash_count_t keys, link_t *item)
00254 {
00255 client_t *client = hash_table_get_instance(item, client_t, link);
00256 return (key[0] == client->in_task_hash);
00257 }
00258
00259 static void client_remove(link_t *item)
00260 {
00261 }
00262
00264 static hash_table_operations_t client_hash_table_ops = {
00265 .hash = client_hash,
00266 .compare = client_compare,
00267 .remove_callback = client_remove
00268 };
00269
00277 static hash_index_t conn_hash(unsigned long key[])
00278 {
00279 assert(key);
00280 return (((key[0]) >> 4) % CONN_HASH_TABLE_BUCKETS);
00281 }
00282
00292 static int conn_compare(unsigned long key[], hash_count_t keys, link_t *item)
00293 {
00294 connection_t *conn = hash_table_get_instance(item, connection_t, link);
00295 return (key[0] == conn->in_phone_hash);
00296 }
00297
00298 static void conn_remove(link_t *item)
00299 {
00300 }
00301
00303 static hash_table_operations_t conn_hash_table_ops = {
00304 .hash = conn_hash,
00305 .compare = conn_compare,
00306 .remove_callback = conn_remove
00307 };
00308
00314 void async_insert_timeout(awaiter_t *wd)
00315 {
00316 wd->to_event.occurred = false;
00317 wd->to_event.inlist = true;
00318
00319 link_t *tmp = timeout_list.next;
00320 while (tmp != &timeout_list) {
00321 awaiter_t *cur
00322 = list_get_instance(tmp, awaiter_t, to_event.link);
00323
00324 if (tv_gteq(&cur->to_event.expires, &wd->to_event.expires))
00325 break;
00326
00327 tmp = tmp->next;
00328 }
00329
00330 list_append(&wd->to_event.link, tmp);
00331 }
00332
00346 static bool route_call(ipc_callid_t callid, ipc_call_t *call)
00347 {
00348 futex_down(&async_futex);
00349
00350 unsigned long key = call->in_phone_hash;
00351 link_t *hlp = hash_table_find(&conn_hash_table, &key);
00352
00353 if (!hlp) {
00354 futex_up(&async_futex);
00355 return false;
00356 }
00357
00358 connection_t *conn = hash_table_get_instance(hlp, connection_t, link);
00359
00360 msg_t *msg = malloc(sizeof(*msg));
00361 if (!msg) {
00362 futex_up(&async_futex);
00363 return false;
00364 }
00365
00366 msg->callid = callid;
00367 msg->call = *call;
00368 list_append(&msg->link, &conn->msg_queue);
00369
00370 if (IPC_GET_IMETHOD(*call) == IPC_M_PHONE_HUNGUP)
00371 conn->close_callid = callid;
00372
00373
00374 if (!conn->wdata.active) {
00375
00376
00377 if (conn->wdata.to_event.inlist) {
00378 conn->wdata.to_event.inlist = false;
00379 list_remove(&conn->wdata.to_event.link);
00380 }
00381
00382 conn->wdata.active = true;
00383 fibril_add_ready(conn->wdata.fid);
00384 }
00385
00386 futex_up(&async_futex);
00387 return true;
00388 }
00389
00400 static int notification_fibril(void *arg)
00401 {
00402 msg_t *msg = (msg_t *) arg;
00403 interrupt_received(msg->callid, &msg->call);
00404
00405 free(msg);
00406 return 0;
00407 }
00408
00420 static bool process_notification(ipc_callid_t callid, ipc_call_t *call)
00421 {
00422 futex_down(&async_futex);
00423
00424 msg_t *msg = malloc(sizeof(*msg));
00425 if (!msg) {
00426 futex_up(&async_futex);
00427 return false;
00428 }
00429
00430 msg->callid = callid;
00431 msg->call = *call;
00432
00433 fid_t fid = fibril_create(notification_fibril, msg);
00434 if (fid == 0) {
00435 free(msg);
00436 futex_up(&async_futex);
00437 return false;
00438 }
00439
00440 fibril_add_ready(fid);
00441
00442 futex_up(&async_futex);
00443 return true;
00444 }
00445
00458 ipc_callid_t async_get_call_timeout(ipc_call_t *call, suseconds_t usecs)
00459 {
00460 assert(FIBRIL_connection);
00461
00462
00463
00464
00465
00466
00467
00468 connection_t *conn = FIBRIL_connection;
00469
00470 futex_down(&async_futex);
00471
00472 if (usecs) {
00473 gettimeofday(&conn->wdata.to_event.expires, NULL);
00474 tv_add(&conn->wdata.to_event.expires, usecs);
00475 } else
00476 conn->wdata.to_event.inlist = false;
00477
00478
00479 while (list_empty(&conn->msg_queue)) {
00480 if (conn->close_callid) {
00481
00482
00483
00484
00485
00486
00487
00488 memset(call, 0, sizeof(ipc_call_t));
00489 IPC_SET_IMETHOD(*call, IPC_M_PHONE_HUNGUP);
00490 futex_up(&async_futex);
00491 return conn->close_callid;
00492 }
00493
00494 if (usecs)
00495 async_insert_timeout(&conn->wdata);
00496
00497 conn->wdata.active = false;
00498
00499
00500
00501
00502
00503
00504
00505 fibril_switch(FIBRIL_TO_MANAGER);
00506
00507
00508
00509
00510
00511 futex_down(&async_futex);
00512 if ((usecs) && (conn->wdata.to_event.occurred)
00513 && (list_empty(&conn->msg_queue))) {
00514
00515 futex_up(&async_futex);
00516 return 0;
00517 }
00518 }
00519
00520 msg_t *msg = list_get_instance(conn->msg_queue.next, msg_t, link);
00521 list_remove(&msg->link);
00522
00523 ipc_callid_t callid = msg->callid;
00524 *call = msg->call;
00525 free(msg);
00526
00527 futex_up(&async_futex);
00528 return callid;
00529 }
00530
00541 static int connection_fibril(void *arg)
00542 {
00543
00544
00545
00546 FIBRIL_connection = (connection_t *) arg;
00547
00548 futex_down(&async_futex);
00549
00550
00551
00552
00553
00554
00555
00556 unsigned long key = FIBRIL_connection->in_task_hash;
00557 link_t *lnk = hash_table_find(&client_hash_table, &key);
00558
00559 client_t *client;
00560
00561 if (lnk) {
00562 client = hash_table_get_instance(lnk, client_t, link);
00563 client->refcnt++;
00564 } else {
00565 client = malloc(sizeof(client_t));
00566 if (!client) {
00567 ipc_answer_0(FIBRIL_connection->callid, ENOMEM);
00568 futex_up(&async_futex);
00569 return 0;
00570 }
00571
00572 client->in_task_hash = FIBRIL_connection->in_task_hash;
00573
00574 async_serialize_start();
00575 client->data = async_client_data_create();
00576 async_serialize_end();
00577
00578 client->refcnt = 1;
00579 hash_table_insert(&client_hash_table, &key, &client->link);
00580 }
00581
00582 futex_up(&async_futex);
00583
00584 FIBRIL_connection->client = client;
00585
00586
00587
00588
00589 FIBRIL_connection->cfibril(FIBRIL_connection->callid,
00590 &FIBRIL_connection->call);
00591
00592
00593
00594
00595 bool destroy;
00596
00597 futex_down(&async_futex);
00598
00599 if (--client->refcnt == 0) {
00600 hash_table_remove(&client_hash_table, &key, 1);
00601 destroy = true;
00602 } else
00603 destroy = false;
00604
00605 futex_up(&async_futex);
00606
00607 if (destroy) {
00608 if (client->data)
00609 async_client_data_destroy(client->data);
00610
00611 free(client);
00612 }
00613
00614
00615
00616
00617 futex_down(&async_futex);
00618 key = FIBRIL_connection->in_phone_hash;
00619 hash_table_remove(&conn_hash_table, &key, 1);
00620 futex_up(&async_futex);
00621
00622
00623
00624
00625 while (!list_empty(&FIBRIL_connection->msg_queue)) {
00626 msg_t *msg =
00627 list_get_instance(FIBRIL_connection->msg_queue.next, msg_t,
00628 link);
00629
00630 list_remove(&msg->link);
00631 ipc_answer_0(msg->callid, EHANGUP);
00632 free(msg);
00633 }
00634
00635
00636
00637
00638
00639 if (FIBRIL_connection->close_callid)
00640 ipc_answer_0(FIBRIL_connection->close_callid, EOK);
00641
00642 free(FIBRIL_connection);
00643 return 0;
00644 }
00645
00665 fid_t async_new_connection(sysarg_t in_task_hash, sysarg_t in_phone_hash,
00666 ipc_callid_t callid, ipc_call_t *call,
00667 void (*cfibril)(ipc_callid_t, ipc_call_t *))
00668 {
00669 connection_t *conn = malloc(sizeof(*conn));
00670 if (!conn) {
00671 if (callid)
00672 ipc_answer_0(callid, ENOMEM);
00673
00674 return (uintptr_t) NULL;
00675 }
00676
00677 conn->in_task_hash = in_task_hash;
00678 conn->in_phone_hash = in_phone_hash;
00679 list_initialize(&conn->msg_queue);
00680 conn->callid = callid;
00681 conn->close_callid = 0;
00682
00683 if (call)
00684 conn->call = *call;
00685
00686
00687 conn->wdata.active = true;
00688 conn->cfibril = cfibril;
00689 conn->wdata.fid = fibril_create(connection_fibril, conn);
00690
00691 if (conn->wdata.fid == 0) {
00692 free(conn);
00693
00694 if (callid)
00695 ipc_answer_0(callid, ENOMEM);
00696
00697 return (uintptr_t) NULL;
00698 }
00699
00700
00701 unsigned long key = conn->in_phone_hash;
00702
00703 futex_down(&async_futex);
00704 hash_table_insert(&conn_hash_table, &key, &conn->link);
00705 futex_up(&async_futex);
00706
00707 fibril_add_ready(conn->wdata.fid);
00708
00709 return conn->wdata.fid;
00710 }
00711
00721 static void handle_call(ipc_callid_t callid, ipc_call_t *call)
00722 {
00723
00724 if ((callid & IPC_CALLID_NOTIFICATION)) {
00725 process_notification(callid, call);
00726 return;
00727 }
00728
00729 switch (IPC_GET_IMETHOD(*call)) {
00730 case IPC_M_CONNECT_ME:
00731 case IPC_M_CONNECT_ME_TO:
00732
00733 async_new_connection(call->in_task_hash, IPC_GET_ARG5(*call),
00734 callid, call, client_connection);
00735 return;
00736 }
00737
00738
00739 if (route_call(callid, call))
00740 return;
00741
00742
00743 ipc_answer_0(callid, EHANGUP);
00744 }
00745
00747 static void handle_expired_timeouts(void)
00748 {
00749 struct timeval tv;
00750 gettimeofday(&tv, NULL);
00751
00752 futex_down(&async_futex);
00753
00754 link_t *cur = timeout_list.next;
00755 while (cur != &timeout_list) {
00756 awaiter_t *waiter =
00757 list_get_instance(cur, awaiter_t, to_event.link);
00758
00759 if (tv_gt(&waiter->to_event.expires, &tv))
00760 break;
00761
00762 cur = cur->next;
00763
00764 list_remove(&waiter->to_event.link);
00765 waiter->to_event.inlist = false;
00766 waiter->to_event.occurred = true;
00767
00768
00769
00770
00771
00772 if (!waiter->active) {
00773 waiter->active = true;
00774 fibril_add_ready(waiter->fid);
00775 }
00776 }
00777
00778 futex_up(&async_futex);
00779 }
00780
00786 static int async_manager_worker(void)
00787 {
00788 while (true) {
00789 if (fibril_switch(FIBRIL_FROM_MANAGER)) {
00790 futex_up(&async_futex);
00791
00792
00793
00794
00795 continue;
00796 }
00797
00798 futex_down(&async_futex);
00799
00800 suseconds_t timeout;
00801 if (!list_empty(&timeout_list)) {
00802 awaiter_t *waiter = list_get_instance(timeout_list.next,
00803 awaiter_t, to_event.link);
00804
00805 struct timeval tv;
00806 gettimeofday(&tv, NULL);
00807
00808 if (tv_gteq(&tv, &waiter->to_event.expires)) {
00809 futex_up(&async_futex);
00810 handle_expired_timeouts();
00811 continue;
00812 } else
00813 timeout = tv_sub(&waiter->to_event.expires, &tv);
00814 } else
00815 timeout = SYNCH_NO_TIMEOUT;
00816
00817 futex_up(&async_futex);
00818
00819 atomic_inc(&threads_in_ipc_wait);
00820
00821 ipc_call_t call;
00822 ipc_callid_t callid = ipc_wait_cycle(&call, timeout,
00823 SYNCH_FLAGS_NONE);
00824
00825 atomic_dec(&threads_in_ipc_wait);
00826
00827 if (!callid) {
00828 handle_expired_timeouts();
00829 continue;
00830 }
00831
00832 if (callid & IPC_CALLID_ANSWERED)
00833 continue;
00834
00835 handle_call(callid, &call);
00836 }
00837
00838 return 0;
00839 }
00840
00849 static int async_manager_fibril(void *arg)
00850 {
00851 futex_up(&async_futex);
00852
00853
00854
00855
00856 async_manager_worker();
00857
00858 return 0;
00859 }
00860
00862 void async_create_manager(void)
00863 {
00864 fid_t fid = fibril_create(async_manager_fibril, NULL);
00865 if (fid != 0)
00866 fibril_add_manager(fid);
00867 }
00868
00870 void async_destroy_manager(void)
00871 {
00872 fibril_remove_manager();
00873 }
00874
00878 void __async_init(void)
00879 {
00880 if (!hash_table_create(&client_hash_table, CLIENT_HASH_TABLE_BUCKETS, 1,
00881 &client_hash_table_ops))
00882 abort();
00883
00884 if (!hash_table_create(&conn_hash_table, CONN_HASH_TABLE_BUCKETS, 1,
00885 &conn_hash_table_ops))
00886 abort();
00887 }
00888
00901 static void reply_received(void *arg, int retval, ipc_call_t *data)
00902 {
00903 futex_down(&async_futex);
00904
00905 amsg_t *msg = (amsg_t *) arg;
00906 msg->retval = retval;
00907
00908
00909 if ((msg->dataptr) && (data))
00910 *msg->dataptr = *data;
00911
00912 write_barrier();
00913
00914
00915 if (msg->wdata.to_event.inlist)
00916 list_remove(&msg->wdata.to_event.link);
00917
00918 msg->done = true;
00919 if (!msg->wdata.active) {
00920 msg->wdata.active = true;
00921 fibril_add_ready(msg->wdata.fid);
00922 }
00923
00924 futex_up(&async_futex);
00925 }
00926
00944 aid_t async_send_fast(int phoneid, sysarg_t method, sysarg_t arg1,
00945 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
00946 {
00947 amsg_t *msg = malloc(sizeof(amsg_t));
00948
00949 if (!msg)
00950 return 0;
00951
00952 msg->done = false;
00953 msg->dataptr = dataptr;
00954
00955 msg->wdata.to_event.inlist = false;
00956
00957
00958
00959
00960
00961 msg->wdata.active = true;
00962
00963 ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, msg,
00964 reply_received, true);
00965
00966 return (aid_t) msg;
00967 }
00968
00987 aid_t async_send_slow(int phoneid, sysarg_t method, sysarg_t arg1,
00988 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
00989 ipc_call_t *dataptr)
00990 {
00991 amsg_t *msg = malloc(sizeof(amsg_t));
00992
00993 if (!msg)
00994 return 0;
00995
00996 msg->done = false;
00997 msg->dataptr = dataptr;
00998
00999 msg->wdata.to_event.inlist = false;
01000
01001
01002
01003
01004
01005 msg->wdata.active = true;
01006
01007 ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, msg,
01008 reply_received, true);
01009
01010 return (aid_t) msg;
01011 }
01012
01020 void async_wait_for(aid_t amsgid, sysarg_t *retval)
01021 {
01022 amsg_t *msg = (amsg_t *) amsgid;
01023
01024 futex_down(&async_futex);
01025 if (msg->done) {
01026 futex_up(&async_futex);
01027 goto done;
01028 }
01029
01030 msg->wdata.fid = fibril_get_id();
01031 msg->wdata.active = false;
01032 msg->wdata.to_event.inlist = false;
01033
01034
01035 fibril_switch(FIBRIL_TO_MANAGER);
01036
01037
01038
01039 done:
01040 if (retval)
01041 *retval = msg->retval;
01042
01043 free(msg);
01044 }
01045
01056 int async_wait_timeout(aid_t amsgid, sysarg_t *retval, suseconds_t timeout)
01057 {
01058 amsg_t *msg = (amsg_t *) amsgid;
01059
01060
01061 if (timeout < 0)
01062 return ETIMEOUT;
01063
01064 futex_down(&async_futex);
01065 if (msg->done) {
01066 futex_up(&async_futex);
01067 goto done;
01068 }
01069
01070 gettimeofday(&msg->wdata.to_event.expires, NULL);
01071 tv_add(&msg->wdata.to_event.expires, timeout);
01072
01073 msg->wdata.fid = fibril_get_id();
01074 msg->wdata.active = false;
01075 async_insert_timeout(&msg->wdata);
01076
01077
01078 fibril_switch(FIBRIL_TO_MANAGER);
01079
01080
01081
01082 if (!msg->done)
01083 return ETIMEOUT;
01084
01085 done:
01086 if (retval)
01087 *retval = msg->retval;
01088
01089 free(msg);
01090
01091 return 0;
01092 }
01093
01101 void async_usleep(suseconds_t timeout)
01102 {
01103 amsg_t *msg = malloc(sizeof(amsg_t));
01104
01105 if (!msg)
01106 return;
01107
01108 msg->wdata.fid = fibril_get_id();
01109 msg->wdata.active = false;
01110
01111 gettimeofday(&msg->wdata.to_event.expires, NULL);
01112 tv_add(&msg->wdata.to_event.expires, timeout);
01113
01114 futex_down(&async_futex);
01115
01116 async_insert_timeout(&msg->wdata);
01117
01118
01119 fibril_switch(FIBRIL_TO_MANAGER);
01120
01121
01122
01123 free(msg);
01124 }
01125
01131 void async_set_client_connection(async_client_conn_t conn)
01132 {
01133 client_connection = conn;
01134 }
01135
01141 void async_set_interrupt_received(async_client_conn_t intr)
01142 {
01143 interrupt_received = intr;
01144 }
01145
01168 sysarg_t async_req_fast(int phoneid, sysarg_t method, sysarg_t arg1,
01169 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t *r1, sysarg_t *r2,
01170 sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
01171 {
01172 ipc_call_t result;
01173 aid_t eid = async_send_4(phoneid, method, arg1, arg2, arg3, arg4,
01174 &result);
01175
01176 sysarg_t rc;
01177 async_wait_for(eid, &rc);
01178
01179 if (r1)
01180 *r1 = IPC_GET_ARG1(result);
01181
01182 if (r2)
01183 *r2 = IPC_GET_ARG2(result);
01184
01185 if (r3)
01186 *r3 = IPC_GET_ARG3(result);
01187
01188 if (r4)
01189 *r4 = IPC_GET_ARG4(result);
01190
01191 if (r5)
01192 *r5 = IPC_GET_ARG5(result);
01193
01194 return rc;
01195 }
01196
01217 sysarg_t async_req_slow(int phoneid, sysarg_t method, sysarg_t arg1,
01218 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, sysarg_t *r1,
01219 sysarg_t *r2, sysarg_t *r3, sysarg_t *r4, sysarg_t *r5)
01220 {
01221 ipc_call_t result;
01222 aid_t eid = async_send_5(phoneid, method, arg1, arg2, arg3, arg4, arg5,
01223 &result);
01224
01225 sysarg_t rc;
01226 async_wait_for(eid, &rc);
01227
01228 if (r1)
01229 *r1 = IPC_GET_ARG1(result);
01230
01231 if (r2)
01232 *r2 = IPC_GET_ARG2(result);
01233
01234 if (r3)
01235 *r3 = IPC_GET_ARG3(result);
01236
01237 if (r4)
01238 *r4 = IPC_GET_ARG4(result);
01239
01240 if (r5)
01241 *r5 = IPC_GET_ARG5(result);
01242
01243 return rc;
01244 }
01245
01246 void async_msg_0(int phone, sysarg_t imethod)
01247 {
01248 ipc_call_async_0(phone, imethod, NULL, NULL, true);
01249 }
01250
01251 void async_msg_1(int phone, sysarg_t imethod, sysarg_t arg1)
01252 {
01253 ipc_call_async_1(phone, imethod, arg1, NULL, NULL, true);
01254 }
01255
01256 void async_msg_2(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2)
01257 {
01258 ipc_call_async_2(phone, imethod, arg1, arg2, NULL, NULL, true);
01259 }
01260
01261 void async_msg_3(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
01262 sysarg_t arg3)
01263 {
01264 ipc_call_async_3(phone, imethod, arg1, arg2, arg3, NULL, NULL, true);
01265 }
01266
01267 void async_msg_4(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
01268 sysarg_t arg3, sysarg_t arg4)
01269 {
01270 ipc_call_async_4(phone, imethod, arg1, arg2, arg3, arg4, NULL, NULL,
01271 true);
01272 }
01273
01274 void async_msg_5(int phone, sysarg_t imethod, sysarg_t arg1, sysarg_t arg2,
01275 sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
01276 {
01277 ipc_call_async_5(phone, imethod, arg1, arg2, arg3, arg4, arg5, NULL,
01278 NULL, true);
01279 }
01280
01281 sysarg_t async_answer_0(ipc_callid_t callid, sysarg_t retval)
01282 {
01283 return ipc_answer_0(callid, retval);
01284 }
01285
01286 sysarg_t async_answer_1(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1)
01287 {
01288 return ipc_answer_1(callid, retval, arg1);
01289 }
01290
01291 sysarg_t async_answer_2(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
01292 sysarg_t arg2)
01293 {
01294 return ipc_answer_2(callid, retval, arg1, arg2);
01295 }
01296
01297 sysarg_t async_answer_3(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
01298 sysarg_t arg2, sysarg_t arg3)
01299 {
01300 return ipc_answer_3(callid, retval, arg1, arg2, arg3);
01301 }
01302
01303 sysarg_t async_answer_4(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
01304 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
01305 {
01306 return ipc_answer_4(callid, retval, arg1, arg2, arg3, arg4);
01307 }
01308
01309 sysarg_t async_answer_5(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
01310 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
01311 {
01312 return ipc_answer_5(callid, retval, arg1, arg2, arg3, arg4, arg5);
01313 }
01314
01315 int async_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
01316 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
01317 {
01318 return ipc_forward_fast(callid, phoneid, imethod, arg1, arg2, mode);
01319 }
01320
01321 int async_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
01322 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
01323 unsigned int mode)
01324 {
01325 return ipc_forward_slow(callid, phoneid, imethod, arg1, arg2, arg3, arg4,
01326 arg5, mode);
01327 }
01328
01342 int async_connect_to_me(int phone, sysarg_t arg1, sysarg_t arg2,
01343 sysarg_t arg3, async_client_conn_t client_receiver)
01344 {
01345 sysarg_t task_hash;
01346 sysarg_t phone_hash;
01347 int rc = async_req_3_5(phone, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
01348 NULL, NULL, NULL, &task_hash, &phone_hash);
01349 if (rc != EOK)
01350 return rc;
01351
01352 if (client_receiver != NULL)
01353 async_new_connection(task_hash, phone_hash, 0, NULL,
01354 client_receiver);
01355
01356 return EOK;
01357 }
01358
01371 int async_connect_me_to(int phone, sysarg_t arg1, sysarg_t arg2,
01372 sysarg_t arg3)
01373 {
01374 sysarg_t newphid;
01375 int rc = async_req_3_5(phone, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
01376 NULL, NULL, NULL, NULL, &newphid);
01377
01378 if (rc != EOK)
01379 return rc;
01380
01381 return newphid;
01382 }
01383
01397 int async_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
01398 sysarg_t arg3)
01399 {
01400 sysarg_t newphid;
01401 int rc = async_req_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
01402 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
01403
01404 if (rc != EOK)
01405 return rc;
01406
01407 return newphid;
01408 }
01409
01413 int async_connect_kbox(task_id_t id)
01414 {
01415 return ipc_connect_kbox(id);
01416 }
01417
01425 int async_hangup(int phone)
01426 {
01427 return ipc_hangup(phone);
01428 }
01429
01431 void async_poke(void)
01432 {
01433 ipc_poke();
01434 }
01435
01447 int async_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
01448 unsigned int *flags)
01449 {
01450 sysarg_t tmp_flags;
01451 int res = async_req_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
01452 (sysarg_t) size, arg, NULL, &tmp_flags);
01453
01454 if (flags)
01455 *flags = (unsigned int) tmp_flags;
01456
01457 return res;
01458 }
01459
01474 bool async_share_in_receive(ipc_callid_t *callid, size_t *size)
01475 {
01476 assert(callid);
01477 assert(size);
01478
01479 ipc_call_t data;
01480 *callid = async_get_call(&data);
01481
01482 if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_IN)
01483 return false;
01484
01485 *size = (size_t) IPC_GET_ARG2(data);
01486 return true;
01487 }
01488
01502 int async_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
01503 {
01504 return ipc_share_in_finalize(callid, src, flags);
01505 }
01506
01516 int async_share_out_start(int phoneid, void *src, unsigned int flags)
01517 {
01518 return async_req_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
01519 (sysarg_t) flags);
01520 }
01521
01537 bool async_share_out_receive(ipc_callid_t *callid, size_t *size, unsigned int *flags)
01538 {
01539 assert(callid);
01540 assert(size);
01541 assert(flags);
01542
01543 ipc_call_t data;
01544 *callid = async_get_call(&data);
01545
01546 if (IPC_GET_IMETHOD(data) != IPC_M_SHARE_OUT)
01547 return false;
01548
01549 *size = (size_t) IPC_GET_ARG2(data);
01550 *flags = (unsigned int) IPC_GET_ARG3(data);
01551 return true;
01552 }
01553
01566 int async_share_out_finalize(ipc_callid_t callid, void *dst)
01567 {
01568 return ipc_share_out_finalize(callid, dst);
01569 }
01570
01579 aid_t async_data_read(int phoneid, void *dst, size_t size, ipc_call_t *dataptr)
01580 {
01581 return async_send_2(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
01582 (sysarg_t) size, dataptr);
01583 }
01584
01595 int
01596 async_data_read_start_generic(int phoneid, void *dst, size_t size, int flags)
01597 {
01598 return async_req_3_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
01599 (sysarg_t) size, (sysarg_t) flags);
01600 }
01601
01616 bool async_data_read_receive(ipc_callid_t *callid, size_t *size)
01617 {
01618 assert(callid);
01619
01620 ipc_call_t data;
01621 *callid = async_get_call(&data);
01622
01623 if (IPC_GET_IMETHOD(data) != IPC_M_DATA_READ)
01624 return false;
01625
01626 if (size)
01627 *size = (size_t) IPC_GET_ARG2(data);
01628
01629 return true;
01630 }
01631
01646 int async_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
01647 {
01648 return ipc_data_read_finalize(callid, src, size);
01649 }
01650
01654 int async_data_read_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
01655 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
01656 {
01657 ipc_callid_t callid;
01658 if (!async_data_read_receive(&callid, NULL)) {
01659 ipc_answer_0(callid, EINVAL);
01660 return EINVAL;
01661 }
01662
01663 aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
01664 dataptr);
01665 if (msg == 0) {
01666 ipc_answer_0(callid, EINVAL);
01667 return EINVAL;
01668 }
01669
01670 int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
01671 IPC_FF_ROUTE_FROM_ME);
01672 if (retval != EOK) {
01673 async_wait_for(msg, NULL);
01674 ipc_answer_0(callid, retval);
01675 return retval;
01676 }
01677
01678 sysarg_t rc;
01679 async_wait_for(msg, &rc);
01680
01681 return (int) rc;
01682 }
01683
01694 int
01695 async_data_write_start_generic(int phoneid, const void *src, size_t size,
01696 int flags)
01697 {
01698 return async_req_3_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
01699 (sysarg_t) size, (sysarg_t) flags);
01700 }
01701
01716 bool async_data_write_receive(ipc_callid_t *callid, size_t *size)
01717 {
01718 assert(callid);
01719
01720 ipc_call_t data;
01721 *callid = async_get_call(&data);
01722
01723 if (IPC_GET_IMETHOD(data) != IPC_M_DATA_WRITE)
01724 return false;
01725
01726 if (size)
01727 *size = (size_t) IPC_GET_ARG2(data);
01728
01729 return true;
01730 }
01731
01745 int async_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
01746 {
01747 return ipc_data_write_finalize(callid, dst, size);
01748 }
01749
01771 int async_data_write_accept(void **data, const bool nullterm,
01772 const size_t min_size, const size_t max_size, const size_t granularity,
01773 size_t *received)
01774 {
01775 ipc_callid_t callid;
01776 size_t size;
01777 if (!async_data_write_receive(&callid, &size)) {
01778 ipc_answer_0(callid, EINVAL);
01779 return EINVAL;
01780 }
01781
01782 if (size < min_size) {
01783 ipc_answer_0(callid, EINVAL);
01784 return EINVAL;
01785 }
01786
01787 if ((max_size > 0) && (size > max_size)) {
01788 ipc_answer_0(callid, EINVAL);
01789 return EINVAL;
01790 }
01791
01792 if ((granularity > 0) && ((size % granularity) != 0)) {
01793 ipc_answer_0(callid, EINVAL);
01794 return EINVAL;
01795 }
01796
01797 void *_data;
01798
01799 if (nullterm)
01800 _data = malloc(size + 1);
01801 else
01802 _data = malloc(size);
01803
01804 if (_data == NULL) {
01805 ipc_answer_0(callid, ENOMEM);
01806 return ENOMEM;
01807 }
01808
01809 int rc = async_data_write_finalize(callid, _data, size);
01810 if (rc != EOK) {
01811 free(_data);
01812 return rc;
01813 }
01814
01815 if (nullterm)
01816 ((char *) _data)[size] = 0;
01817
01818 *data = _data;
01819 if (received != NULL)
01820 *received = size;
01821
01822 return EOK;
01823 }
01824
01832 void async_data_write_void(sysarg_t retval)
01833 {
01834 ipc_callid_t callid;
01835 async_data_write_receive(&callid, NULL);
01836 ipc_answer_0(callid, retval);
01837 }
01838
01842 int async_data_write_forward_fast(int phoneid, sysarg_t method, sysarg_t arg1,
01843 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, ipc_call_t *dataptr)
01844 {
01845 ipc_callid_t callid;
01846 if (!async_data_write_receive(&callid, NULL)) {
01847 ipc_answer_0(callid, EINVAL);
01848 return EINVAL;
01849 }
01850
01851 aid_t msg = async_send_fast(phoneid, method, arg1, arg2, arg3, arg4,
01852 dataptr);
01853 if (msg == 0) {
01854 ipc_answer_0(callid, EINVAL);
01855 return EINVAL;
01856 }
01857
01858 int retval = ipc_forward_fast(callid, phoneid, 0, 0, 0,
01859 IPC_FF_ROUTE_FROM_ME);
01860 if (retval != EOK) {
01861 async_wait_for(msg, NULL);
01862 ipc_answer_0(callid, retval);
01863 return retval;
01864 }
01865
01866 sysarg_t rc;
01867 async_wait_for(msg, &rc);
01868
01869 return (int) rc;
01870 }
01871