source: mainline/uspace/lib/c/generic/ipc.c@ f044e96

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f044e96 was ab34cc9, checked in by Jakub Jermar <jakub@…>, 14 years ago

Make IPC_M_CONNECT_TO_ME more consistent with IPC_M_CONNECT_TO_ME.

  • Instead of passing the task ID of the connecting task in IPC argument 3 and 4, pass it in ipc_call_t::in_task_id.
  • Actually, all answers are signed by the answering task ID like this.
  • Property mode set to 100644
File size: 25.9 KB
RevLine 
[b419162]1/*
[df4ed85]2 * Copyright (c) 2006 Ondrej Palkovsky
[b419162]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.
[b2951e2]27 */
28
29/** @addtogroup libc
30 * @{
31 * @}
32 */
33
[fadd381]34/** @addtogroup libcipc IPC
[b2951e2]35 * @brief HelenOS uspace IPC
36 * @{
37 * @ingroup libc
38 */
39/** @file
[6b10dab]40 */
[b419162]41
[7ee6aff]42#include <ipc/ipc.h>
[b419162]43#include <libc.h>
[936351c1]44#include <malloc.h>
45#include <errno.h>
[d9c8c81]46#include <adt/list.h>
[35509652]47#include <futex.h>
[bc1f1c2]48#include <fibril.h>
[633bcc6]49#include <macros.h>
[b419162]50
[36c9234]51/**
[10477601]52 * Structures of this type are used for keeping track
53 * of sent asynchronous calls and queing unsent calls.
[936351c1]54 */
55typedef struct {
56 link_t list;
[10477601]57
[936351c1]58 ipc_async_callback_t callback;
59 void *private;
[10477601]60
[936351c1]61 union {
62 ipc_callid_t callid;
63 struct {
[4c61e60]64 ipc_call_t data;
[936351c1]65 int phoneid;
66 } msg;
[8b243f2]67 } u;
[10477601]68
69 /** Fibril waiting for sending this call. */
70 fid_t fid;
[936351c1]71} async_call_t;
72
73LIST_INITIALIZE(dispatched_calls);
[fc42b28]74
[8b243f2]75/** List of asynchronous calls that were not accepted by kernel.
76 *
[10477601]77 * Protected by async_futex, because if the call is not accepted
78 * by the kernel, the async framework is used automatically.
79 *
[fc42b28]80 */
[8b243f2]81LIST_INITIALIZE(queued_calls);
[936351c1]82
[80649a91]83static atomic_t ipc_futex = FUTEX_INITIALIZER;
[35509652]84
[10477601]85/** Fast synchronous call.
86 *
87 * Only three payload arguments can be passed using this function. However,
88 * this function is faster than the generic ipc_call_sync_slow() because
89 * the payload is passed directly in registers.
90 *
91 * @param phoneid Phone handle for the call.
92 * @param method Requested method.
93 * @param arg1 Service-defined payload argument.
94 * @param arg2 Service-defined payload argument.
95 * @param arg3 Service-defined payload argument.
96 * @param result1 If non-NULL, the return ARG1 will be stored there.
97 * @param result2 If non-NULL, the return ARG2 will be stored there.
98 * @param result3 If non-NULL, the return ARG3 will be stored there.
99 * @param result4 If non-NULL, the return ARG4 will be stored there.
100 * @param result5 If non-NULL, the return ARG5 will be stored there.
101 *
102 * @return Negative values representing IPC errors.
103 * @return Otherwise the RETVAL of the answer.
104 *
105 */
106int ipc_call_sync_fast(int phoneid, sysarg_t method, sysarg_t arg1,
107 sysarg_t arg2, sysarg_t arg3, sysarg_t *result1, sysarg_t *result2,
108 sysarg_t *result3, sysarg_t *result4, sysarg_t *result5)
[b419162]109{
[4c61e60]110 ipc_call_t resdata;
[10477601]111 int callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
[2e51969]112 arg2, arg3, (sysarg_t) &resdata);
[06502f7d]113 if (callres)
114 return callres;
[10477601]115
[2e51969]116 if (result1)
117 *result1 = IPC_GET_ARG1(resdata);
118 if (result2)
119 *result2 = IPC_GET_ARG2(resdata);
120 if (result3)
121 *result3 = IPC_GET_ARG3(resdata);
122 if (result4)
123 *result4 = IPC_GET_ARG4(resdata);
124 if (result5)
125 *result5 = IPC_GET_ARG5(resdata);
[10477601]126
[06502f7d]127 return IPC_GET_RETVAL(resdata);
[b419162]128}
129
[10477601]130/** Synchronous call transmitting 5 arguments of payload.
[8b243f2]131 *
[228e490]132 * @param phoneid Phone handle for the call.
133 * @param imethod Requested interface and method.
134 * @param arg1 Service-defined payload argument.
135 * @param arg2 Service-defined payload argument.
136 * @param arg3 Service-defined payload argument.
137 * @param arg4 Service-defined payload argument.
138 * @param arg5 Service-defined payload argument.
139 * @param result1 If non-NULL, storage for the first return argument.
140 * @param result2 If non-NULL, storage for the second return argument.
141 * @param result3 If non-NULL, storage for the third return argument.
142 * @param result4 If non-NULL, storage for the fourth return argument.
143 * @param result5 If non-NULL, storage for the fifth return argument.
144 *
[10477601]145 * @return Negative values representing IPC errors.
146 * @return Otherwise the RETVAL of the answer.
[228e490]147 *
[8b243f2]148 */
[10477601]149int ipc_call_sync_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
150 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
151 sysarg_t *result1, sysarg_t *result2, sysarg_t *result3, sysarg_t *result4,
152 sysarg_t *result5)
[06502f7d]153{
[4c61e60]154 ipc_call_t data;
[228e490]155
156 IPC_SET_IMETHOD(data, imethod);
[06502f7d]157 IPC_SET_ARG1(data, arg1);
158 IPC_SET_ARG2(data, arg2);
159 IPC_SET_ARG3(data, arg3);
[2e51969]160 IPC_SET_ARG4(data, arg4);
161 IPC_SET_ARG5(data, arg5);
[228e490]162
163 int callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid,
164 (sysarg_t) &data, (sysarg_t) &data);
[06502f7d]165 if (callres)
166 return callres;
[228e490]167
[06502f7d]168 if (result1)
169 *result1 = IPC_GET_ARG1(data);
170 if (result2)
171 *result2 = IPC_GET_ARG2(data);
172 if (result3)
173 *result3 = IPC_GET_ARG3(data);
[2e51969]174 if (result4)
175 *result4 = IPC_GET_ARG4(data);
176 if (result5)
177 *result5 = IPC_GET_ARG5(data);
[228e490]178
[06502f7d]179 return IPC_GET_RETVAL(data);
180}
181
[10477601]182/** Send asynchronous message via syscall.
[8b243f2]183 *
[228e490]184 * @param phoneid Phone handle for the call.
185 * @param data Call data with the request.
186 *
187 * @return Hash of the call or an error code.
[8b243f2]188 *
189 */
[10477601]190static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
[936351c1]191{
[3209923]192 return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
[936351c1]193}
194
[10477601]195/** Prolog for ipc_call_async_*() functions.
196 *
197 * @param private Argument for the answer/error callback.
198 * @param callback Answer/error callback.
[8b243f2]199 *
[10477601]200 * @return New, partially initialized async_call structure or NULL.
[8b243f2]201 *
202 */
203static inline async_call_t *ipc_prepare_async(void *private,
204 ipc_async_callback_t callback)
[b419162]205{
[10477601]206 async_call_t *call =
207 (async_call_t *) malloc(sizeof(async_call_t));
[936351c1]208 if (!call) {
[a784a96]209 if (callback)
210 callback(private, ENOMEM, NULL);
[10477601]211
[c1d2c9d]212 return NULL;
[936351c1]213 }
[10477601]214
[fc42b28]215 call->callback = callback;
216 call->private = private;
[10477601]217
[c1d2c9d]218 return call;
219}
220
[10477601]221/** Epilog for ipc_call_async_*() functions.
222 *
223 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
224 * @param phoneid Phone handle through which the call was made.
225 * @param call Structure returned by ipc_prepare_async().
226 * @param can_preempt If true, the current fibril can be preempted
227 * in this call.
[8b243f2]228 *
229 */
230static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
[10477601]231 async_call_t *call, bool can_preempt)
[c1d2c9d]232{
[10477601]233 if (!call) {
234 /* Nothing to do regardless if failed or not */
[d8b42fb2]235 futex_up(&ipc_futex);
236 return;
237 }
[10477601]238
[b78d0bd]239 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
[fc42b28]240 futex_up(&ipc_futex);
[10477601]241
[06502f7d]242 /* Call asynchronous handler with error code */
[c1d2c9d]243 if (call->callback)
244 call->callback(call->private, ENOENT, NULL);
[10477601]245
[936351c1]246 free(call);
[06502f7d]247 return;
248 }
[10477601]249
[b78d0bd]250 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
[fc42b28]251 futex_up(&ipc_futex);
[10477601]252
[936351c1]253 call->u.msg.phoneid = phoneid;
[b1f51f0]254
[fc42b28]255 futex_down(&async_futex);
[936351c1]256 list_append(&call->list, &queued_calls);
[10477601]257
[b1f51f0]258 if (can_preempt) {
[bc1f1c2]259 call->fid = fibril_get_id();
[116d3f6f]260 fibril_switch(FIBRIL_TO_MANAGER);
[b1f51f0]261 /* Async futex unlocked by previous call */
262 } else {
[bc1f1c2]263 call->fid = 0;
[b1f51f0]264 futex_up(&async_futex);
265 }
[10477601]266
[06502f7d]267 return;
268 }
[10477601]269
[936351c1]270 call->u.callid = callid;
[10477601]271
[8b243f2]272 /* Add call to the list of dispatched calls */
[936351c1]273 list_append(&call->list, &dispatched_calls);
[35509652]274 futex_up(&ipc_futex);
[c1d2c9d]275}
276
[10477601]277/** Fast asynchronous call.
[8b243f2]278 *
[3209923]279 * This function can only handle four arguments of payload. It is, however,
280 * faster than the more generic ipc_call_async_slow().
[8b243f2]281 *
282 * Note that this function is a void function.
[10477601]283 *
284 * During normal operation, answering this call will trigger the callback.
285 * In case of fatal error, the callback handler is called with the proper
286 * error code. If the call cannot be temporarily made, it is queued.
[c1d2c9d]287 *
[228e490]288 * @param phoneid Phone handle for the call.
289 * @param imethod Requested interface and method.
290 * @param arg1 Service-defined payload argument.
291 * @param arg2 Service-defined payload argument.
292 * @param arg3 Service-defined payload argument.
293 * @param arg4 Service-defined payload argument.
294 * @param private Argument to be passed to the answer/error callback.
295 * @param callback Answer or error callback.
[10477601]296 * @param can_preempt If true, the current fibril will be preempted in
[228e490]297 * case the kernel temporarily refuses to accept more
298 * asynchronous calls.
299 *
[c1d2c9d]300 */
[228e490]301void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
[96b02eb9]302 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
[10477601]303 ipc_async_callback_t callback, bool can_preempt)
[c1d2c9d]304{
[d8b42fb2]305 async_call_t *call = NULL;
[228e490]306
[d8b42fb2]307 if (callback) {
308 call = ipc_prepare_async(private, callback);
309 if (!call)
310 return;
311 }
[228e490]312
[8b243f2]313 /*
[10477601]314 * We need to make sure that we get callid
315 * before another thread accesses the queue again.
[8b243f2]316 */
[10477601]317
[c1d2c9d]318 futex_down(&ipc_futex);
[228e490]319 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
320 imethod, arg1, arg2, arg3, arg4);
321
[b78d0bd]322 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
[d8b42fb2]323 if (!call) {
324 call = ipc_prepare_async(private, callback);
325 if (!call)
326 return;
327 }
[10477601]328
[228e490]329 IPC_SET_IMETHOD(call->u.msg.data, imethod);
[c1d2c9d]330 IPC_SET_ARG1(call->u.msg.data, arg1);
331 IPC_SET_ARG2(call->u.msg.data, arg2);
[3209923]332 IPC_SET_ARG3(call->u.msg.data, arg3);
333 IPC_SET_ARG4(call->u.msg.data, arg4);
[10477601]334
[8498915]335 /*
336 * To achieve deterministic behavior, we always zero out the
337 * arguments that are beyond the limits of the fast version.
338 */
[10477601]339
[8498915]340 IPC_SET_ARG5(call->u.msg.data, 0);
[c1d2c9d]341 }
[10477601]342
[b1f51f0]343 ipc_finish_async(callid, phoneid, call, can_preempt);
[c1d2c9d]344}
345
[10477601]346/** Asynchronous call transmitting the entire payload.
[8b243f2]347 *
348 * Note that this function is a void function.
[10477601]349 *
350 * During normal operation, answering this call will trigger the callback.
351 * In case of fatal error, the callback handler is called with the proper
352 * error code. If the call cannot be temporarily made, it is queued.
[8b243f2]353 *
[228e490]354 * @param phoneid Phone handle for the call.
355 * @param imethod Requested interface and method.
356 * @param arg1 Service-defined payload argument.
357 * @param arg2 Service-defined payload argument.
358 * @param arg3 Service-defined payload argument.
359 * @param arg4 Service-defined payload argument.
360 * @param arg5 Service-defined payload argument.
361 * @param private Argument to be passed to the answer/error callback.
362 * @param callback Answer or error callback.
[10477601]363 * @param can_preempt If true, the current fibril will be preempted in
[228e490]364 * case the kernel temporarily refuses to accept more
365 * asynchronous calls.
[c1d2c9d]366 *
367 */
[228e490]368void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
[96b02eb9]369 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
[10477601]370 ipc_async_callback_t callback, bool can_preempt)
[c1d2c9d]371{
[10477601]372 async_call_t *call = ipc_prepare_async(private, callback);
[c1d2c9d]373 if (!call)
374 return;
[10477601]375
[228e490]376 IPC_SET_IMETHOD(call->u.msg.data, imethod);
[c1d2c9d]377 IPC_SET_ARG1(call->u.msg.data, arg1);
378 IPC_SET_ARG2(call->u.msg.data, arg2);
379 IPC_SET_ARG3(call->u.msg.data, arg3);
[3209923]380 IPC_SET_ARG4(call->u.msg.data, arg4);
381 IPC_SET_ARG5(call->u.msg.data, arg5);
[10477601]382
[8b243f2]383 /*
[10477601]384 * We need to make sure that we get callid
385 * before another threadaccesses the queue again.
[8b243f2]386 */
[10477601]387
[c1d2c9d]388 futex_down(&ipc_futex);
[10477601]389 ipc_callid_t callid =
390 ipc_call_async_internal(phoneid, &call->u.msg.data);
391
[b1f51f0]392 ipc_finish_async(callid, phoneid, call, can_preempt);
[b419162]393}
394
[10477601]395/** Answer received call (fast version).
[250717cc]396 *
[b74959bd]397 * The fast answer makes use of passing retval and first four arguments in
398 * registers. If you need to return more, use the ipc_answer_slow() instead.
[250717cc]399 *
[10477601]400 * @param callid Hash of the call being answered.
401 * @param retval Return value.
402 * @param arg1 First return argument.
403 * @param arg2 Second return argument.
404 * @param arg3 Third return argument.
405 * @param arg4 Fourth return argument.
406 *
407 * @return Zero on success.
408 * @return Value from @ref errno.h on failure.
[250717cc]409 *
410 */
[96b02eb9]411sysarg_t ipc_answer_fast(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
412 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
[b419162]413{
[b74959bd]414 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
415 arg4);
[b419162]416}
[06502f7d]417
[10477601]418/** Answer received call (entire payload).
419 *
420 * @param callid Hash of the call being answered.
421 * @param retval Return value.
422 * @param arg1 First return argument.
423 * @param arg2 Second return argument.
424 * @param arg3 Third return argument.
425 * @param arg4 Fourth return argument.
426 * @param arg5 Fifth return argument.
[250717cc]427 *
[10477601]428 * @return Zero on success.
429 * @return Value from @ref errno.h on failure.
[250717cc]430 *
431 */
[96b02eb9]432sysarg_t ipc_answer_slow(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
433 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
[250717cc]434{
[b74959bd]435 ipc_call_t data;
[10477601]436
[b74959bd]437 IPC_SET_RETVAL(data, retval);
438 IPC_SET_ARG1(data, arg1);
439 IPC_SET_ARG2(data, arg2);
440 IPC_SET_ARG3(data, arg3);
441 IPC_SET_ARG4(data, arg4);
442 IPC_SET_ARG5(data, arg5);
[10477601]443
[b74959bd]444 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
[250717cc]445}
446
[10477601]447/** Try to dispatch queued calls from the async queue.
448 *
449 */
450static void dispatch_queued_calls(void)
[936351c1]451{
[8b243f2]452 /** @todo
[10477601]453 * Integrate intelligently ipc_futex so that it is locked during
454 * ipc_call_async_*() until it is added to dispatched_calls.
[fc42b28]455 */
[10477601]456
[fc42b28]457 futex_down(&async_futex);
[10477601]458
[936351c1]459 while (!list_empty(&queued_calls)) {
[10477601]460 async_call_t *call =
[b72efe8]461 list_get_instance(list_first(&queued_calls), async_call_t, list);
[10477601]462 ipc_callid_t callid =
463 ipc_call_async_internal(call->u.msg.phoneid, &call->u.msg.data);
464
465 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY)
[936351c1]466 break;
[10477601]467
[936351c1]468 list_remove(&call->list);
[10477601]469
[fc42b28]470 futex_up(&async_futex);
[10477601]471
[bc1f1c2]472 if (call->fid)
473 fibril_add_ready(call->fid);
[fc42b28]474
[b78d0bd]475 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
[a784a96]476 if (call->callback)
477 call->callback(call->private, ENOENT, NULL);
[10477601]478
[936351c1]479 free(call);
480 } else {
481 call->u.callid = callid;
[10477601]482
[fc42b28]483 futex_down(&ipc_futex);
[936351c1]484 list_append(&call->list, &dispatched_calls);
[fc42b28]485 futex_up(&ipc_futex);
[936351c1]486 }
[10477601]487
[fc42b28]488 futex_down(&async_futex);
[936351c1]489 }
[10477601]490
[fc42b28]491 futex_up(&async_futex);
[936351c1]492}
493
[10477601]494/** Handle received answer.
[936351c1]495 *
[8b243f2]496 * Find the hash of the answer and call the answer callback.
[936351c1]497 *
[10477601]498 * The answer has the same hash as the request OR'ed with
499 * the IPC_CALLID_ANSWERED bit.
500 *
501 * @todo Use hash table.
502 *
503 * @param callid Hash of the received answer.
504 * @param data Call data of the answer.
[8b243f2]505 *
[936351c1]506 */
[4c61e60]507static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
[936351c1]508{
509 callid &= ~IPC_CALLID_ANSWERED;
510
[35509652]511 futex_down(&ipc_futex);
[10477601]512
513 link_t *item;
[b72efe8]514 for (item = dispatched_calls.head.next; item != &dispatched_calls.head;
[8b243f2]515 item = item->next) {
[10477601]516 async_call_t *call =
517 list_get_instance(item, async_call_t, list);
518
[936351c1]519 if (call->u.callid == callid) {
520 list_remove(&call->list);
[10477601]521
[35509652]522 futex_up(&ipc_futex);
[10477601]523
[a784a96]524 if (call->callback)
[10477601]525 call->callback(call->private,
[8b243f2]526 IPC_GET_RETVAL(*data), data);
[10477601]527
[a784a96]528 free(call);
[936351c1]529 return;
530 }
531 }
[10477601]532
[35509652]533 futex_up(&ipc_futex);
[936351c1]534}
535
[10477601]536/** Wait for first IPC call to come.
537 *
538 * @param call Incoming call storage.
539 * @param usec Timeout in microseconds
540 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
[8b243f2]541 *
[10477601]542 * @return Hash of the call. Note that certain bits have special
543 * meaning: IPC_CALLID_ANSWERED is set in an answer
544 * and IPC_CALLID_NOTIFICATION is used for notifications.
[b419162]545 *
546 */
[10477601]547ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
548 unsigned int flags)
[b419162]549{
[10477601]550 ipc_callid_t callid =
551 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
552
[80649a91]553 /* Handle received answers */
[fc42b28]554 if (callid & IPC_CALLID_ANSWERED) {
[80649a91]555 handle_answer(callid, call);
[10477601]556 dispatch_queued_calls();
[fc42b28]557 }
[10477601]558
[04a73cdf]559 return callid;
560}
561
[10477601]562/** Interrupt one thread of this task from waiting for IPC.
[04a73cdf]563 *
[10477601]564 */
565void ipc_poke(void)
566{
567 __SYSCALL0(SYS_IPC_POKE);
568}
569
570/** Wait for first IPC call to come.
[8b243f2]571 *
[10477601]572 * Only requests are returned, answers are processed internally.
573 *
574 * @param call Incoming call storage.
575 * @param usec Timeout in microseconds
576 *
577 * @return Hash of the call.
[096ba7a]578 *
[04a73cdf]579 */
[10477601]580ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
[04a73cdf]581{
582 ipc_callid_t callid;
[10477601]583
[04a73cdf]584 do {
[2d22049]585 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
[04a73cdf]586 } while (callid & IPC_CALLID_ANSWERED);
[10477601]587
[04a73cdf]588 return callid;
589}
590
591/** Check if there is an IPC call waiting to be picked up.
592 *
[10477601]593 * Only requests are returned, answers are processed internally.
594 *
595 * @param call Incoming call storage.
596 *
597 * @return Hash of the call.
598 *
[04a73cdf]599 */
600ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
601{
602 ipc_callid_t callid;
[10477601]603
[04a73cdf]604 do {
[8b243f2]605 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
606 SYNCH_FLAGS_NON_BLOCKING);
[06502f7d]607 } while (callid & IPC_CALLID_ANSWERED);
[10477601]608
[b419162]609 return callid;
610}
[5106e98]611
[10477601]612/** Request callback connection.
613 *
[633bcc6]614 * The @a task_id and @a phonehash identifiers returned
[10477601]615 * by the kernel can be used for connection tracking.
[4c61e60]616 *
[10477601]617 * @param phoneid Phone handle used for contacting the other side.
618 * @param arg1 User defined argument.
619 * @param arg2 User defined argument.
620 * @param arg3 User defined argument.
[633bcc6]621 * @param task_id Identifier of the client task.
[10477601]622 * @param phonehash Opaque identifier of the phone that will
623 * be used for incoming calls.
624 *
625 * @return Zero on success or a negative error code.
[8b243f2]626 *
[4c61e60]627 */
[10477601]628int ipc_connect_to_me(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
[633bcc6]629 task_id_t *task_id, sysarg_t *phonehash)
[5106e98]630{
[ab34cc9]631 ipc_call_t data;
632 int rc = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid,
633 IPC_M_CONNECT_TO_ME, arg1, arg2, arg3, (sysarg_t) &data);
634 if (rc == EOK) {
635 *task_id = data.in_task_id;
636 *phonehash = IPC_GET_ARG5(data);
637 }
[633bcc6]638 return rc;
[5106e98]639}
[11eae82]640
[79ae36dd]641/** Request cloned connection.
642 *
643 * @param phoneid Phone handle used for contacting the other side.
644 *
645 * @return Cloned phone handle on success or a negative error code.
646 *
647 */
648int ipc_connect_me(int phoneid)
649{
650 sysarg_t newphid;
651 int res = ipc_call_sync_0_5(phoneid, IPC_M_CONNECT_ME, NULL, NULL,
652 NULL, NULL, &newphid);
653 if (res)
654 return res;
655
656 return newphid;
657}
658
[10477601]659/** Request new connection.
660 *
661 * @param phoneid Phone handle used for contacting the other side.
662 * @param arg1 User defined argument.
663 * @param arg2 User defined argument.
664 * @param arg3 User defined argument.
[4c61e60]665 *
[10477601]666 * @return New phone handle on success or a negative error code.
[51ec40f]667 *
[4c61e60]668 */
[10477601]669int ipc_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
[11eae82]670{
[96b02eb9]671 sysarg_t newphid;
[10477601]672 int res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
[90c35436]673 NULL, NULL, NULL, NULL, &newphid);
[4c61e60]674 if (res)
675 return res;
[10477601]676
[4c61e60]677 return newphid;
[11eae82]678}
679
[10477601]680/** Request new connection (blocking)
[19b28b0]681 *
682 * If the connection is not available at the moment, the
[10477601]683 * call should block. This has to be, however, implemented
684 * on the server side.
685 *
686 * @param phoneid Phone handle used for contacting the other side.
687 * @param arg1 User defined argument.
688 * @param arg2 User defined argument.
689 * @param arg3 User defined argument.
[19b28b0]690 *
[10477601]691 * @return New phone handle on success or a negative error code.
[19b28b0]692 *
693 */
[10477601]694int ipc_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
695 sysarg_t arg3)
[19b28b0]696{
[96b02eb9]697 sysarg_t newphid;
[10477601]698 int res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
[19b28b0]699 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
700 if (res)
701 return res;
[10477601]702
[19b28b0]703 return newphid;
704}
705
[8b243f2]706/** Hang up a phone.
707 *
[10477601]708 * @param phoneid Handle of the phone to be hung up.
709 *
710 * @return Zero on success or a negative error code.
[8b243f2]711 *
712 */
[7048773]713int ipc_hangup(int phoneid)
714{
715 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
716}
[6180b57]717
[8b243f2]718/** Forward a received call to another destination.
[10477601]719 *
720 * For non-system methods, the old method, arg1 and arg2 are rewritten
721 * by the new values. For system methods, the new method, arg1 and arg2
722 * are written to the old arg1, arg2 and arg3, respectivelly. Calls with
723 * immutable methods are forwarded verbatim.
[8b243f2]724 *
[228e490]725 * @param callid Hash of the call to forward.
726 * @param phoneid Phone handle to use for forwarding.
727 * @param imethod New interface and method for the forwarded call.
728 * @param arg1 New value of the first argument for the forwarded call.
729 * @param arg2 New value of the second argument for the forwarded call.
730 * @param mode Flags specifying mode of the forward operation.
[8b243f2]731 *
[228e490]732 * @return Zero on success or an error code.
[8b243f2]733 *
734 */
[10477601]735int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
736 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
[043dcc27]737{
[228e490]738 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
[90c35436]739 arg2, mode);
[043dcc27]740}
741
[10477601]742int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
[96b02eb9]743 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
[10477601]744 unsigned int mode)
[48daf64]745{
746 ipc_call_t data;
[228e490]747
748 IPC_SET_IMETHOD(data, imethod);
[48daf64]749 IPC_SET_ARG1(data, arg1);
750 IPC_SET_ARG2(data, arg2);
751 IPC_SET_ARG3(data, arg3);
752 IPC_SET_ARG4(data, arg4);
753 IPC_SET_ARG5(data, arg5);
[228e490]754
[10477601]755 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
756 mode);
[48daf64]757}
758
[10477601]759/** Wrapper for IPC_M_SHARE_IN calls.
760 *
761 * @param phoneid Phone that will be used to contact the receiving side.
762 * @param dst Destination address space area base.
763 * @param size Size of the destination address space area.
764 * @param arg User defined argument.
765 * @param flags Storage for received flags. Can be NULL.
[27d293a]766 *
[10477601]767 * @return Zero on success or a negative error code from errno.h.
[27d293a]768 *
769 */
[96b02eb9]770int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
[10477601]771 unsigned int *flags)
[27d293a]772{
[36e9cd1]773 sysarg_t tmp_flags = 0;
[96b02eb9]774 int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
775 (sysarg_t) size, arg, NULL, &tmp_flags);
[36e9cd1]776
[27d293a]777 if (flags)
[10477601]778 *flags = (unsigned int) tmp_flags;
[36e9cd1]779
[27d293a]780 return res;
781}
782
783/** Wrapper for answering the IPC_M_SHARE_IN calls.
784 *
[10477601]785 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
786 * calls so that the user doesn't have to remember the meaning of each
787 * IPC argument.
[27d293a]788 *
[10477601]789 * @param callid Hash of the IPC_M_DATA_READ call to answer.
790 * @param src Source address space base.
791 * @param flags Flags to be used for sharing. Bits can be only cleared.
792 *
793 * @return Zero on success or a value from @ref errno.h on failure.
[27d293a]794 *
795 */
[10477601]796int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
[27d293a]797{
[96b02eb9]798 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
[27d293a]799}
800
[10477601]801/** Wrapper for IPC_M_SHARE_OUT calls.
802 *
803 * @param phoneid Phone that will be used to contact the receiving side.
804 * @param src Source address space area base address.
805 * @param flags Flags to be used for sharing. Bits can be only cleared.
[27d293a]806 *
[10477601]807 * @return Zero on success or a negative error code from errno.h.
[27d293a]808 *
809 */
[10477601]810int ipc_share_out_start(int phoneid, void *src, unsigned int flags)
[27d293a]811{
[96b02eb9]812 return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
813 (sysarg_t) flags);
[27d293a]814}
815
816/** Wrapper for answering the IPC_M_SHARE_OUT calls.
817 *
[10477601]818 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT
819 * calls so that the user doesn't have to remember the meaning of each
820 * IPC argument.
[27d293a]821 *
[10477601]822 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.
823 * @param dst Destination address space area base address.
824 *
825 * @return Zero on success or a value from @ref errno.h on failure.
[27d293a]826 *
827 */
[215e375]828int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
[27d293a]829{
[96b02eb9]830 return ipc_answer_1(callid, EOK, (sysarg_t) dst);
[27d293a]831}
832
[10477601]833/** Wrapper for IPC_M_DATA_READ calls.
[a55d5f9f]834 *
[10477601]835 * @param phoneid Phone that will be used to contact the receiving side.
836 * @param dst Address of the beginning of the destination buffer.
837 * @param size Size of the destination buffer.
838 *
839 * @return Zero on success or a negative error code from errno.h.
[a55d5f9f]840 *
841 */
[215e375]842int ipc_data_read_start(int phoneid, void *dst, size_t size)
[a55d5f9f]843{
[96b02eb9]844 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
845 (sysarg_t) size);
[a55d5f9f]846}
847
848/** Wrapper for answering the IPC_M_DATA_READ calls.
849 *
[10477601]850 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
851 * calls so that the user doesn't have to remember the meaning of each
852 * IPC argument.
853 *
854 * @param callid Hash of the IPC_M_DATA_READ call to answer.
855 * @param src Source address for the IPC_M_DATA_READ call.
856 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than
857 * the maximum size announced by the sender.
[a55d5f9f]858 *
[10477601]859 * @return Zero on success or a value from @ref errno.h on failure.
[a55d5f9f]860 *
861 */
[c61d34b]862int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
[a55d5f9f]863{
[96b02eb9]864 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size);
[a55d5f9f]865}
866
[10477601]867/** Wrapper for IPC_M_DATA_WRITE calls.
[183b4a0]868 *
[10477601]869 * @param phoneid Phone that will be used to contact the receiving side.
870 * @param src Address of the beginning of the source buffer.
871 * @param size Size of the source buffer.
872 *
873 * @return Zero on success or a negative error code from errno.h.
[26f2af0]874 *
875 */
[c61d34b]876int ipc_data_write_start(int phoneid, const void *src, size_t size)
[26f2af0]877{
[96b02eb9]878 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
879 (sysarg_t) size);
[26f2af0]880}
881
[36d852c]882/** Wrapper for answering the IPC_M_DATA_WRITE calls.
[183b4a0]883 *
[10477601]884 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE
885 * calls so that the user doesn't have to remember the meaning of each
886 * IPC argument.
887 *
888 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.
889 * @param dst Final destination address for the IPC_M_DATA_WRITE call.
890 * @param size Final size for the IPC_M_DATA_WRITE call.
[183b4a0]891 *
[10477601]892 * @return Zero on success or a value from @ref errno.h on failure.
[183b4a0]893 *
894 */
[215e375]895int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
[183b4a0]896{
[96b02eb9]897 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size);
[183b4a0]898}
[9a1b20c]899
900/** Connect to a task specified by id.
[6b10dab]901 *
[9a1b20c]902 */
903int ipc_connect_kbox(task_id_t id)
904{
[6b10dab]905#ifdef __32_BITS__
906 sysarg64_t arg = (sysarg64_t) id;
[9a1b20c]907 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
[6b10dab]908#endif
909
910#ifdef __64_BITS__
911 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
912#endif
[9a1b20c]913}
[6b10dab]914
[fadd381]915/** @}
[b2951e2]916 */
Note: See TracBrowser for help on using the repository browser.