source: mainline/uspace/lib/libc/generic/ipc.c@ c7509e5

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

Improve comments in async.c

  • Property mode set to 100644
File size: 16.8 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
[b419162]40 */
41
[7ee6aff]42#include <ipc/ipc.h>
[b419162]43#include <libc.h>
[936351c1]44#include <malloc.h>
45#include <errno.h>
[7ee6aff]46#include <libadt/list.h>
[936351c1]47#include <stdio.h>
48#include <unistd.h>
[35509652]49#include <futex.h>
[04a73cdf]50#include <kernel/synch/synch.h>
[fc42b28]51#include <async.h>
[bc1f1c2]52#include <fibril.h>
[b419162]53
[36c9234]54/**
55 * Structures of this type are used for keeping track of sent asynchronous calls
56 * and queing unsent calls.
[936351c1]57 */
58typedef struct {
59 link_t list;
60
61 ipc_async_callback_t callback;
62 void *private;
63 union {
64 ipc_callid_t callid;
65 struct {
[4c61e60]66 ipc_call_t data;
[936351c1]67 int phoneid;
68 } msg;
[8b243f2]69 } u;
[bc1f1c2]70 fid_t fid; /**< Fibril waiting for sending this call. */
[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 *
77 * It is protected by async_futex, because if the call cannot be sent into the
78 * kernel, the async framework is used automatically.
[fc42b28]79 */
[8b243f2]80LIST_INITIALIZE(queued_calls);
[936351c1]81
[80649a91]82static atomic_t ipc_futex = FUTEX_INITIALIZER;
[35509652]83
[8b243f2]84/** Make a fast synchronous call.
85 *
86 * Only one payload argument can be passed using this function. However, this
87 * function is faster than the generic ipc_call_sync_3().
88 *
89 * @param phoneid Phone handle for the call.
90 * @param method Requested method.
91 * @param arg1 Service-defined payload argument.
92 * @param result If non-NULL, the return ARG1 will be stored there.
93 *
94 * @return Negative values represent errors returned by IPC.
95 * Otherwise the RETVAL of the answer is returned.
96 */
97int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result)
[b419162]98{
[4c61e60]99 ipc_call_t resdata;
[06502f7d]100 int callres;
101
[936351c1]102 callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
[8b243f2]103 (sysarg_t) &resdata);
[06502f7d]104 if (callres)
105 return callres;
106 if (result)
107 *result = IPC_GET_ARG1(resdata);
108 return IPC_GET_RETVAL(resdata);
[b419162]109}
110
[8b243f2]111/** Make a synchronous call transmitting 3 arguments of payload.
112 *
113 * @param phoneid Phone handle for the call.
114 * @param method Requested method.
115 * @param arg1 Service-defined payload argument.
116 * @param arg2 Service-defined payload argument.
117 * @param arg3 Service-defined payload argument.
118 * @param result1 If non-NULL, storage for the first return argument.
119 * @param result2 If non-NULL, storage for the second return argument.
120 * @param result3 If non-NULL, storage for the third return argument.
121 *
122 * @return Negative value means IPC error.
123 * Otherwise the RETVAL of the answer.
124 */
125int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
126 ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
[06502f7d]127{
[4c61e60]128 ipc_call_t data;
[06502f7d]129 int callres;
130
131 IPC_SET_METHOD(data, method);
132 IPC_SET_ARG1(data, arg1);
133 IPC_SET_ARG2(data, arg2);
134 IPC_SET_ARG3(data, arg3);
135
[8b243f2]136 callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,
137 (sysarg_t) &data);
[06502f7d]138 if (callres)
139 return callres;
140
141 if (result1)
142 *result1 = IPC_GET_ARG1(data);
143 if (result2)
144 *result2 = IPC_GET_ARG2(data);
145 if (result3)
146 *result3 = IPC_GET_ARG3(data);
147 return IPC_GET_RETVAL(data);
148}
149
[8b243f2]150/** Syscall to send asynchronous message.
151 *
152 * @param phoneid Phone handle for the call.
153 * @param data Call data with the request.
154 *
155 * @return Hash of the call or an error code.
156 */
157static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
[936351c1]158{
[8b243f2]159 return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data);
[936351c1]160}
161
[8b243f2]162/** Prolog to ipc_call_async_*() functions.
163 *
164 * @param private Argument for the answer/error callback.
165 * @param callback Answer/error callback.
166 *
167 * @return New, partially initialized async_call structure or NULL.
168 */
169static inline async_call_t *ipc_prepare_async(void *private,
170 ipc_async_callback_t callback)
[b419162]171{
[936351c1]172 async_call_t *call;
[06502f7d]173
[936351c1]174 call = malloc(sizeof(*call));
175 if (!call) {
[a784a96]176 if (callback)
177 callback(private, ENOMEM, NULL);
[c1d2c9d]178 return NULL;
[936351c1]179 }
[fc42b28]180 call->callback = callback;
181 call->private = private;
182
[c1d2c9d]183 return call;
184}
185
[8b243f2]186/** Epilogue of ipc_call_async_*() functions.
187 *
188 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
189 * @param phoneid Phone handle through which the call was made.
190 * @param call async_call structure returned by ipc_prepare_async().
191 * @param can_preempt If non-zero, the current pseudo thread can be preempted
192 * in this call.
193 */
194static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
195 async_call_t *call, int can_preempt)
[c1d2c9d]196{
[d8b42fb2]197 if (!call) { /* Nothing to do regardless if failed or not */
198 futex_up(&ipc_futex);
199 return;
200 }
201
[06502f7d]202 if (callid == IPC_CALLRET_FATAL) {
[fc42b28]203 futex_up(&ipc_futex);
[06502f7d]204 /* Call asynchronous handler with error code */
[c1d2c9d]205 if (call->callback)
206 call->callback(call->private, ENOENT, NULL);
[936351c1]207 free(call);
[06502f7d]208 return;
209 }
[936351c1]210
[06502f7d]211 if (callid == IPC_CALLRET_TEMPORARY) {
[fc42b28]212 futex_up(&ipc_futex);
213
[936351c1]214 call->u.msg.phoneid = phoneid;
[b1f51f0]215
[fc42b28]216 futex_down(&async_futex);
[936351c1]217 list_append(&call->list, &queued_calls);
[fc42b28]218
[b1f51f0]219 if (can_preempt) {
[bc1f1c2]220 call->fid = fibril_get_id();
221 fibril_schedule_next_adv(FIBRIL_TO_MANAGER);
[b1f51f0]222 /* Async futex unlocked by previous call */
223 } else {
[bc1f1c2]224 call->fid = 0;
[b1f51f0]225 futex_up(&async_futex);
226 }
[06502f7d]227 return;
228 }
[936351c1]229 call->u.callid = callid;
[8b243f2]230 /* Add call to the list of dispatched calls */
[936351c1]231 list_append(&call->list, &dispatched_calls);
[35509652]232 futex_up(&ipc_futex);
[c1d2c9d]233
234}
235
[8b243f2]236/** Make a fast asynchronous call.
237 *
238 * This function can only handle two arguments of payload. It is, however,
239 * faster than the more generic ipc_call_async_3().
240 *
241 * Note that this function is a void function.
242 * During normal opertation, answering this call will trigger the callback.
243 * In case of fatal error, call the callback handler with the proper error code.
244 * If the call cannot be temporarily made, queue it.
[c1d2c9d]245 *
[8b243f2]246 * @param phoneid Phone handle for the call.
247 * @param method Requested method.
248 * @param arg1 Service-defined payload argument.
249 * @param arg2 Service-defined payload argument.
250 * @param private Argument to be passed to the answer/error callback.
251 * @param callback Answer or error callback.
252 * @param can_preempt If non-zero, the current pseudo thread will be preempted
253 * in case the kernel temporarily refuses to accept more
254 * asynchronous calls.
[c1d2c9d]255 */
256void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
[8b243f2]257 ipcarg_t arg2, void *private, ipc_async_callback_t callback,
258 int can_preempt)
[c1d2c9d]259{
[d8b42fb2]260 async_call_t *call = NULL;
[c1d2c9d]261 ipc_callid_t callid;
262
[d8b42fb2]263 if (callback) {
264 call = ipc_prepare_async(private, callback);
265 if (!call)
266 return;
267 }
[c1d2c9d]268
[8b243f2]269 /*
270 * We need to make sure that we get callid before another thread
271 * accesses the queue again.
272 */
[c1d2c9d]273 futex_down(&ipc_futex);
[8b243f2]274 callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
275 arg2);
[c1d2c9d]276
277 if (callid == IPC_CALLRET_TEMPORARY) {
[d8b42fb2]278 if (!call) {
279 call = ipc_prepare_async(private, callback);
280 if (!call)
281 return;
282 }
[c1d2c9d]283 IPC_SET_METHOD(call->u.msg.data, method);
284 IPC_SET_ARG1(call->u.msg.data, arg1);
285 IPC_SET_ARG2(call->u.msg.data, arg2);
286 }
[b1f51f0]287 ipc_finish_async(callid, phoneid, call, can_preempt);
[c1d2c9d]288}
289
[8b243f2]290/** Make an asynchronous call transmitting the entire payload.
291 *
292 * Note that this function is a void function.
293 * During normal opertation, answering this call will trigger the callback.
294 * In case of fatal error, call the callback handler with the proper error code.
295 * If the call cannot be temporarily made, queue it.
296 *
297 * @param phoneid Phone handle for the call.
298 * @param method Requested method.
299 * @param arg1 Service-defined payload argument.
300 * @param arg2 Service-defined payload argument.
301 * @param arg3 Service-defined payload argument.
302 * @param private Argument to be passed to the answer/error callback.
303 * @param callback Answer or error callback.
304 * @param can_preempt If non-zero, the current pseudo thread will be preempted
305 * in case the kernel temporarily refuses to accept more
306 * asynchronous calls.
[c1d2c9d]307 *
308 */
309void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
[8b243f2]310 ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback,
311 int can_preempt)
[c1d2c9d]312{
313 async_call_t *call;
314 ipc_callid_t callid;
315
316 call = ipc_prepare_async(private, callback);
317 if (!call)
318 return;
319
320 IPC_SET_METHOD(call->u.msg.data, method);
321 IPC_SET_ARG1(call->u.msg.data, arg1);
322 IPC_SET_ARG2(call->u.msg.data, arg2);
323 IPC_SET_ARG3(call->u.msg.data, arg3);
[8b243f2]324 /*
325 * We need to make sure that we get callid before another thread accesses
326 * the queue again.
327 */
[c1d2c9d]328 futex_down(&ipc_futex);
329 callid = _ipc_call_async(phoneid, &call->u.msg.data);
330
[b1f51f0]331 ipc_finish_async(callid, phoneid, call, can_preempt);
[b419162]332}
333
[06502f7d]334
[8b243f2]335/** Answer a received call - fast version.
[250717cc]336 *
[8b243f2]337 * The fast answer makes use of passing retval and first two arguments in
338 * registers. If you need to return more, use the ipc_answer() instead.
[250717cc]339 *
[8b243f2]340 * @param callid Hash of the call being answered.
341 * @param retval Return value.
342 * @param arg1 First return argument.
343 * @param arg2 Second return argument.
[250717cc]344 *
[8b243f2]345 * @return Zero on success or a value from @ref errno.h on failure.
[250717cc]346 */
347ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
[8b243f2]348 ipcarg_t arg2)
[b419162]349{
[8a568e3]350 return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
[b419162]351}
[06502f7d]352
[8b243f2]353/** Answer a received call - full version.
[250717cc]354 *
[8b243f2]355 * @param callid Hash of the call being answered.
356 * @param call Call structure with the answer.
357 * Must be already initialized by the responder.
[250717cc]358 *
[8b243f2]359 * @return Zero on success or a value from @ref errno.h on failure.
[250717cc]360 */
361ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
362{
363 return __SYSCALL2(SYS_IPC_ANSWER, callid, (sysarg_t) call);
364}
365
366
[8b243f2]367/** Try to dispatch queued calls from the async queue. */
[936351c1]368static void try_dispatch_queued_calls(void)
369{
370 async_call_t *call;
371 ipc_callid_t callid;
372
[8b243f2]373 /** @todo
374 * Integrate intelligently ipc_futex, so that it is locked during
375 * ipc_call_async_*(), until it is added to dispatched_calls.
[fc42b28]376 */
377 futex_down(&async_futex);
[936351c1]378 while (!list_empty(&queued_calls)) {
[8b243f2]379 call = list_get_instance(queued_calls.next, async_call_t, list);
380 callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data);
[fc42b28]381 if (callid == IPC_CALLRET_TEMPORARY) {
[936351c1]382 break;
[fc42b28]383 }
[936351c1]384 list_remove(&call->list);
[35509652]385
[fc42b28]386 futex_up(&async_futex);
[bc1f1c2]387 if (call->fid)
388 fibril_add_ready(call->fid);
[fc42b28]389
[936351c1]390 if (callid == IPC_CALLRET_FATAL) {
[a784a96]391 if (call->callback)
392 call->callback(call->private, ENOENT, NULL);
[936351c1]393 free(call);
394 } else {
395 call->u.callid = callid;
[fc42b28]396 futex_down(&ipc_futex);
[936351c1]397 list_append(&call->list, &dispatched_calls);
[fc42b28]398 futex_up(&ipc_futex);
[936351c1]399 }
[fc42b28]400 futex_down(&async_futex);
[936351c1]401 }
[fc42b28]402 futex_up(&async_futex);
[936351c1]403}
404
[8b243f2]405/** Handle a received answer.
[936351c1]406 *
[8b243f2]407 * Find the hash of the answer and call the answer callback.
[936351c1]408 *
[8b243f2]409 * @todo Make it use hash table.
410 *
411 * @param callid Hash of the received answer.
412 * The answer has the same hash as the request OR'ed with
413 * the IPC_CALLID_ANSWERED bit.
414 * @param data Call data of the answer.
[936351c1]415 */
[4c61e60]416static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
[936351c1]417{
418 link_t *item;
419 async_call_t *call;
420
421 callid &= ~IPC_CALLID_ANSWERED;
422
[35509652]423 futex_down(&ipc_futex);
[936351c1]424 for (item = dispatched_calls.next; item != &dispatched_calls;
[8b243f2]425 item = item->next) {
[936351c1]426 call = list_get_instance(item, async_call_t, list);
427 if (call->u.callid == callid) {
428 list_remove(&call->list);
[35509652]429 futex_up(&ipc_futex);
[a784a96]430 if (call->callback)
431 call->callback(call->private,
[8b243f2]432 IPC_GET_RETVAL(*data), data);
[a784a96]433 free(call);
[936351c1]434 return;
435 }
436 }
[35509652]437 futex_up(&ipc_futex);
[936351c1]438}
439
440
[8b243f2]441/** Wait for a first call to come.
442 *
443 * @param call Storage where the incoming call data will be stored.
444 * @param usec Timeout in microseconds
445 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
[b419162]446 *
[8b243f2]447 * @return Hash of the call. Note that certain bits have special
448 * meaning. IPC_CALLID_ANSWERED will be set in an answer
449 * and IPC_CALLID_NOTIFICATION is used for notifications.
450 *
[b419162]451 */
[80649a91]452ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
[b419162]453{
454 ipc_callid_t callid;
455
[80649a91]456 callid = __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
457 /* Handle received answers */
[fc42b28]458 if (callid & IPC_CALLID_ANSWERED) {
[80649a91]459 handle_answer(callid, call);
[fc42b28]460 try_dispatch_queued_calls();
461 }
[04a73cdf]462
463 return callid;
464}
465
466/** Wait some time for an IPC call.
467 *
[8b243f2]468 * The call will return after an answer is received.
469 *
470 * @param call Storage where the incoming call data will be stored.
471 * @param usec Timeout in microseconds.
[096ba7a]472 *
[8b243f2]473 * @return Hash of the answer.
[04a73cdf]474 */
475ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
476{
477 ipc_callid_t callid;
478
479 do {
[2d22049]480 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
[04a73cdf]481 } while (callid & IPC_CALLID_ANSWERED);
482
483 return callid;
484}
485
486/** Check if there is an IPC call waiting to be picked up.
487 *
[8b243f2]488 * @param call Storage where the incoming call will be stored.
489 * @return Hash of the answer.
[04a73cdf]490 */
491ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
492{
493 ipc_callid_t callid;
494
495 do {
[8b243f2]496 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
497 SYNCH_FLAGS_NON_BLOCKING);
[06502f7d]498 } while (callid & IPC_CALLID_ANSWERED);
[936351c1]499
[b419162]500 return callid;
501}
[5106e98]502
[51ec40f]503/** Ask destination to do a callback connection.
[4c61e60]504 *
[8b243f2]505 * @param phoneid Phone handle used for contacting the other side.
506 * @param arg1 Service-defined argument.
507 * @param arg2 Service-defined argument.
508 * @param phonehash Storage where the library will store an opaque
[51ec40f]509 * identifier of the phone that will be used for incoming
[8b243f2]510 * calls. This identifier can be used for connection
511 * tracking.
512 *
513 * @return Zero on success or a negative error code.
[4c61e60]514 */
[51ec40f]515int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
[5106e98]516{
[51ec40f]517 return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0,
518 phonehash);
[5106e98]519}
[11eae82]520
[51ec40f]521/** Ask through phone for a new connection to some service.
[4c61e60]522 *
[8b243f2]523 * @param phoneid Phone handle used for contacting the other side.
[51ec40f]524 * @param arg1 User defined argument.
525 * @param arg2 User defined argument.
526 *
[8b243f2]527 * @return New phone handle on success or a negative error code.
[4c61e60]528 */
[11eae82]529int ipc_connect_me_to(int phoneid, int arg1, int arg2)
530{
[06b0d112]531 ipcarg_t newphid;
[4c61e60]532 int res;
533
[51ec40f]534 res = ipc_call_sync_3(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, 0, 0, 0,
535 &newphid);
[4c61e60]536 if (res)
537 return res;
538 return newphid;
[11eae82]539}
540
[8b243f2]541/** Hang up a phone.
542 *
543 * @param phoneid Handle of the phone to be hung up.
544 *
545 * @return Zero on success or a negative error code.
546 */
[7048773]547int ipc_hangup(int phoneid)
548{
549 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
550}
[6180b57]551
[2b017ba]552/** Register IRQ notification.
553 *
[8b243f2]554 * @param inr IRQ number.
555 * @param devno Device number of the device generating inr.
556 * @param method Use this method for notifying me.
557 * @param ucode Top-half pseudocode handler.
[2b017ba]558 *
[8b243f2]559 * @return Value returned by the kernel.
[2b017ba]560 */
561int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
[6180b57]562{
[8b243f2]563 return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
564 (sysarg_t) ucode);
[6180b57]565}
566
[2b017ba]567/** Unregister IRQ notification.
568 *
[8b243f2]569 * @param inr IRQ number.
570 * @param devno Device number of the device generating inr.
[2b017ba]571 *
[8b243f2]572 * @return Value returned by the kernel.
[2b017ba]573 */
574int ipc_unregister_irq(int inr, int devno)
[6180b57]575{
[2b017ba]576 return __SYSCALL2(SYS_IPC_UNREGISTER_IRQ, inr, devno);
[6180b57]577}
[8a568e3]578
[8b243f2]579/** Forward a received call to another destination.
580 *
581 * @param callid Hash of the call to forward.
582 * @param phoneid Phone handle to use for forwarding.
583 * @param method New method for the forwarded call.
584 * @param arg1 New value of the first argument for the forwarded call.
585 *
586 * @return Zero on success or an error code.
587 *
588 * For non-system methods, the old method and arg1 are rewritten by the new
589 * values. For system methods, the new method and arg1 are written to the old
590 * arg1 and arg2, respectivelly.
591 */
[043dcc27]592int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
593{
594 return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
595}
596
[fadd381]597/** @}
[b2951e2]598 */
Note: See TracBrowser for help on using the repository browser.