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
00042 #include <ipc/ipc.h>
00043 #include <libc.h>
00044 #include <malloc.h>
00045 #include <errno.h>
00046 #include <adt/list.h>
00047 #include <futex.h>
00048 #include <fibril.h>
00049
00054 typedef struct {
00055 link_t list;
00056
00057 ipc_async_callback_t callback;
00058 void *private;
00059
00060 union {
00061 ipc_callid_t callid;
00062 struct {
00063 ipc_call_t data;
00064 int phoneid;
00065 } msg;
00066 } u;
00067
00069 fid_t fid;
00070 } async_call_t;
00071
00072 LIST_INITIALIZE(dispatched_calls);
00073
00080 LIST_INITIALIZE(queued_calls);
00081
00082 static atomic_t ipc_futex = FUTEX_INITIALIZER;
00083
00105 int ipc_call_sync_fast(int phoneid, sysarg_t method, sysarg_t arg1,
00106 sysarg_t arg2, sysarg_t arg3, sysarg_t *result1, sysarg_t *result2,
00107 sysarg_t *result3, sysarg_t *result4, sysarg_t *result5)
00108 {
00109 ipc_call_t resdata;
00110 int callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
00111 arg2, arg3, (sysarg_t) &resdata);
00112 if (callres)
00113 return callres;
00114
00115 if (result1)
00116 *result1 = IPC_GET_ARG1(resdata);
00117 if (result2)
00118 *result2 = IPC_GET_ARG2(resdata);
00119 if (result3)
00120 *result3 = IPC_GET_ARG3(resdata);
00121 if (result4)
00122 *result4 = IPC_GET_ARG4(resdata);
00123 if (result5)
00124 *result5 = IPC_GET_ARG5(resdata);
00125
00126 return IPC_GET_RETVAL(resdata);
00127 }
00128
00148 int ipc_call_sync_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
00149 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
00150 sysarg_t *result1, sysarg_t *result2, sysarg_t *result3, sysarg_t *result4,
00151 sysarg_t *result5)
00152 {
00153 ipc_call_t data;
00154
00155 IPC_SET_IMETHOD(data, imethod);
00156 IPC_SET_ARG1(data, arg1);
00157 IPC_SET_ARG2(data, arg2);
00158 IPC_SET_ARG3(data, arg3);
00159 IPC_SET_ARG4(data, arg4);
00160 IPC_SET_ARG5(data, arg5);
00161
00162 int callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid,
00163 (sysarg_t) &data, (sysarg_t) &data);
00164 if (callres)
00165 return callres;
00166
00167 if (result1)
00168 *result1 = IPC_GET_ARG1(data);
00169 if (result2)
00170 *result2 = IPC_GET_ARG2(data);
00171 if (result3)
00172 *result3 = IPC_GET_ARG3(data);
00173 if (result4)
00174 *result4 = IPC_GET_ARG4(data);
00175 if (result5)
00176 *result5 = IPC_GET_ARG5(data);
00177
00178 return IPC_GET_RETVAL(data);
00179 }
00180
00189 static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
00190 {
00191 return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
00192 }
00193
00202 static inline async_call_t *ipc_prepare_async(void *private,
00203 ipc_async_callback_t callback)
00204 {
00205 async_call_t *call =
00206 (async_call_t *) malloc(sizeof(async_call_t));
00207 if (!call) {
00208 if (callback)
00209 callback(private, ENOMEM, NULL);
00210
00211 return NULL;
00212 }
00213
00214 call->callback = callback;
00215 call->private = private;
00216
00217 return call;
00218 }
00219
00229 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
00230 async_call_t *call, bool can_preempt)
00231 {
00232 if (!call) {
00233
00234 futex_up(&ipc_futex);
00235 return;
00236 }
00237
00238 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
00239 futex_up(&ipc_futex);
00240
00241
00242 if (call->callback)
00243 call->callback(call->private, ENOENT, NULL);
00244
00245 free(call);
00246 return;
00247 }
00248
00249 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
00250 futex_up(&ipc_futex);
00251
00252 call->u.msg.phoneid = phoneid;
00253
00254 futex_down(&async_futex);
00255 list_append(&call->list, &queued_calls);
00256
00257 if (can_preempt) {
00258 call->fid = fibril_get_id();
00259 fibril_switch(FIBRIL_TO_MANAGER);
00260
00261 } else {
00262 call->fid = 0;
00263 futex_up(&async_futex);
00264 }
00265
00266 return;
00267 }
00268
00269 call->u.callid = callid;
00270
00271
00272 list_append(&call->list, &dispatched_calls);
00273 futex_up(&ipc_futex);
00274 }
00275
00300 void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
00301 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
00302 ipc_async_callback_t callback, bool can_preempt)
00303 {
00304 async_call_t *call = NULL;
00305
00306 if (callback) {
00307 call = ipc_prepare_async(private, callback);
00308 if (!call)
00309 return;
00310 }
00311
00312
00313
00314
00315
00316
00317 futex_down(&ipc_futex);
00318 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
00319 imethod, arg1, arg2, arg3, arg4);
00320
00321 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
00322 if (!call) {
00323 call = ipc_prepare_async(private, callback);
00324 if (!call)
00325 return;
00326 }
00327
00328 IPC_SET_IMETHOD(call->u.msg.data, imethod);
00329 IPC_SET_ARG1(call->u.msg.data, arg1);
00330 IPC_SET_ARG2(call->u.msg.data, arg2);
00331 IPC_SET_ARG3(call->u.msg.data, arg3);
00332 IPC_SET_ARG4(call->u.msg.data, arg4);
00333
00334
00335
00336
00337
00338
00339 IPC_SET_ARG5(call->u.msg.data, 0);
00340 }
00341
00342 ipc_finish_async(callid, phoneid, call, can_preempt);
00343 }
00344
00367 void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
00368 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
00369 ipc_async_callback_t callback, bool can_preempt)
00370 {
00371 async_call_t *call = ipc_prepare_async(private, callback);
00372 if (!call)
00373 return;
00374
00375 IPC_SET_IMETHOD(call->u.msg.data, imethod);
00376 IPC_SET_ARG1(call->u.msg.data, arg1);
00377 IPC_SET_ARG2(call->u.msg.data, arg2);
00378 IPC_SET_ARG3(call->u.msg.data, arg3);
00379 IPC_SET_ARG4(call->u.msg.data, arg4);
00380 IPC_SET_ARG5(call->u.msg.data, arg5);
00381
00382
00383
00384
00385
00386
00387 futex_down(&ipc_futex);
00388 ipc_callid_t callid =
00389 ipc_call_async_internal(phoneid, &call->u.msg.data);
00390
00391 ipc_finish_async(callid, phoneid, call, can_preempt);
00392 }
00393
00410 sysarg_t ipc_answer_fast(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
00411 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
00412 {
00413 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
00414 arg4);
00415 }
00416
00431 sysarg_t ipc_answer_slow(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
00432 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
00433 {
00434 ipc_call_t data;
00435
00436 IPC_SET_RETVAL(data, retval);
00437 IPC_SET_ARG1(data, arg1);
00438 IPC_SET_ARG2(data, arg2);
00439 IPC_SET_ARG3(data, arg3);
00440 IPC_SET_ARG4(data, arg4);
00441 IPC_SET_ARG5(data, arg5);
00442
00443 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
00444 }
00445
00449 static void dispatch_queued_calls(void)
00450 {
00456 futex_down(&async_futex);
00457
00458 while (!list_empty(&queued_calls)) {
00459 async_call_t *call =
00460 list_get_instance(queued_calls.next, async_call_t, list);
00461 ipc_callid_t callid =
00462 ipc_call_async_internal(call->u.msg.phoneid, &call->u.msg.data);
00463
00464 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY)
00465 break;
00466
00467 list_remove(&call->list);
00468
00469 futex_up(&async_futex);
00470
00471 if (call->fid)
00472 fibril_add_ready(call->fid);
00473
00474 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
00475 if (call->callback)
00476 call->callback(call->private, ENOENT, NULL);
00477
00478 free(call);
00479 } else {
00480 call->u.callid = callid;
00481
00482 futex_down(&ipc_futex);
00483 list_append(&call->list, &dispatched_calls);
00484 futex_up(&ipc_futex);
00485 }
00486
00487 futex_down(&async_futex);
00488 }
00489
00490 futex_up(&async_futex);
00491 }
00492
00506 static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
00507 {
00508 callid &= ~IPC_CALLID_ANSWERED;
00509
00510 futex_down(&ipc_futex);
00511
00512 link_t *item;
00513 for (item = dispatched_calls.next; item != &dispatched_calls;
00514 item = item->next) {
00515 async_call_t *call =
00516 list_get_instance(item, async_call_t, list);
00517
00518 if (call->u.callid == callid) {
00519 list_remove(&call->list);
00520
00521 futex_up(&ipc_futex);
00522
00523 if (call->callback)
00524 call->callback(call->private,
00525 IPC_GET_RETVAL(*data), data);
00526
00527 free(call);
00528 return;
00529 }
00530 }
00531
00532 futex_up(&ipc_futex);
00533 }
00534
00546 ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
00547 unsigned int flags)
00548 {
00549 ipc_callid_t callid =
00550 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
00551
00552
00553 if (callid & IPC_CALLID_ANSWERED) {
00554 handle_answer(callid, call);
00555 dispatch_queued_calls();
00556 }
00557
00558 return callid;
00559 }
00560
00564 void ipc_poke(void)
00565 {
00566 __SYSCALL0(SYS_IPC_POKE);
00567 }
00568
00579 ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
00580 {
00581 ipc_callid_t callid;
00582
00583 do {
00584 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
00585 } while (callid & IPC_CALLID_ANSWERED);
00586
00587 return callid;
00588 }
00589
00599 ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
00600 {
00601 ipc_callid_t callid;
00602
00603 do {
00604 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
00605 SYNCH_FLAGS_NON_BLOCKING);
00606 } while (callid & IPC_CALLID_ANSWERED);
00607
00608 return callid;
00609 }
00610
00627 int ipc_connect_to_me(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
00628 sysarg_t *taskhash, sysarg_t *phonehash)
00629 {
00630 return ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2,
00631 arg3, NULL, NULL, NULL, taskhash, phonehash);
00632 }
00633
00644 int ipc_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
00645 {
00646 sysarg_t newphid;
00647 int res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
00648 NULL, NULL, NULL, NULL, &newphid);
00649 if (res)
00650 return res;
00651
00652 return newphid;
00653 }
00654
00669 int ipc_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
00670 sysarg_t arg3)
00671 {
00672 sysarg_t newphid;
00673 int res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
00674 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
00675 if (res)
00676 return res;
00677
00678 return newphid;
00679 }
00680
00688 int ipc_hangup(int phoneid)
00689 {
00690 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
00691 }
00692
00710 int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
00711 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
00712 {
00713 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
00714 arg2, mode);
00715 }
00716
00717 int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
00718 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
00719 unsigned int mode)
00720 {
00721 ipc_call_t data;
00722
00723 IPC_SET_IMETHOD(data, imethod);
00724 IPC_SET_ARG1(data, arg1);
00725 IPC_SET_ARG2(data, arg2);
00726 IPC_SET_ARG3(data, arg3);
00727 IPC_SET_ARG4(data, arg4);
00728 IPC_SET_ARG5(data, arg5);
00729
00730 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
00731 mode);
00732 }
00733
00745 int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
00746 unsigned int *flags)
00747 {
00748 sysarg_t tmp_flags = 0;
00749 int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
00750 (sysarg_t) size, arg, NULL, &tmp_flags);
00751
00752 if (flags)
00753 *flags = (unsigned int) tmp_flags;
00754
00755 return res;
00756 }
00757
00771 int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
00772 {
00773 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
00774 }
00775
00785 int ipc_share_out_start(int phoneid, void *src, unsigned int flags)
00786 {
00787 return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
00788 (sysarg_t) flags);
00789 }
00790
00803 int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
00804 {
00805 return ipc_answer_1(callid, EOK, (sysarg_t) dst);
00806 }
00807
00817 int ipc_data_read_start(int phoneid, void *dst, size_t size)
00818 {
00819 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
00820 (sysarg_t) size);
00821 }
00822
00837 int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
00838 {
00839 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size);
00840 }
00841
00851 int ipc_data_write_start(int phoneid, const void *src, size_t size)
00852 {
00853 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
00854 (sysarg_t) size);
00855 }
00856
00870 int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
00871 {
00872 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size);
00873 }
00874
00878 int ipc_connect_kbox(task_id_t id)
00879 {
00880 #ifdef __32_BITS__
00881 sysarg64_t arg = (sysarg64_t) id;
00882 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
00883 #endif
00884
00885 #ifdef __64_BITS__
00886 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
00887 #endif
00888 }
00889