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

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

Do not create a new fibril for each IRQ notification

In the absence of fibril serialization, manager fibrils can
theoretically block in async IPC or on fibril synchronization
primitives. Consequently, it is safe to execute the IRQ handler directly
from the manager fibril. The manager fibril can block while processing
the notification, but most of the times it will not block and the
handler will execute atomically.

This changeset modifies the current behaviour so that we no longer spawn
a new notification fibril for each IRQ, but rather execute the handler
directly from the manager fibril and test if the execution blocked. If
it blocked, the manager fibril had assumed the role of a notification
fibril and we destroy it afterwards - merely to avoid fibril population
explosion. Otherwise, which is the usual behavior, we keep it so that
it resumes its job of a manager fibril.

  • Property mode set to 100644
File size: 15.0 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
[927a181e]83static futex_t ipc_futex = FUTEX_INITIALIZER;
[35509652]84
[10477601]85/** Send asynchronous message via syscall.
[8b243f2]86 *
[228e490]87 * @param phoneid Phone handle for the call.
88 * @param data Call data with the request.
89 *
90 * @return Hash of the call or an error code.
[8b243f2]91 *
92 */
[10477601]93static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
[936351c1]94{
[3209923]95 return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
[936351c1]96}
97
[c170438]98/** Prologue for ipc_call_async_*() functions.
[10477601]99 *
100 * @param private Argument for the answer/error callback.
101 * @param callback Answer/error callback.
[8b243f2]102 *
[10477601]103 * @return New, partially initialized async_call structure or NULL.
[8b243f2]104 *
105 */
106static inline async_call_t *ipc_prepare_async(void *private,
107 ipc_async_callback_t callback)
[b419162]108{
[10477601]109 async_call_t *call =
110 (async_call_t *) malloc(sizeof(async_call_t));
[936351c1]111 if (!call) {
[a784a96]112 if (callback)
113 callback(private, ENOMEM, NULL);
[10477601]114
[c1d2c9d]115 return NULL;
[936351c1]116 }
[10477601]117
[fc42b28]118 call->callback = callback;
119 call->private = private;
[10477601]120
[c1d2c9d]121 return call;
122}
123
[c170438]124/** Epilogue for ipc_call_async_*() functions.
[10477601]125 *
126 * @param callid Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
127 * @param phoneid Phone handle through which the call was made.
128 * @param call Structure returned by ipc_prepare_async().
[8b243f2]129 */
130static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
[dcc150cb]131 async_call_t *call)
[c1d2c9d]132{
[10477601]133 if (!call) {
134 /* Nothing to do regardless if failed or not */
[cdbcf14]135 futex_unlock(&ipc_futex);
[d8b42fb2]136 return;
137 }
[10477601]138
[b78d0bd]139 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
[cdbcf14]140 futex_unlock(&ipc_futex);
[10477601]141
[06502f7d]142 /* Call asynchronous handler with error code */
[c1d2c9d]143 if (call->callback)
144 call->callback(call->private, ENOENT, NULL);
[10477601]145
[936351c1]146 free(call);
[06502f7d]147 return;
148 }
[10477601]149
[b78d0bd]150 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
[cdbcf14]151 futex_unlock(&ipc_futex);
[10477601]152
[936351c1]153 call->u.msg.phoneid = phoneid;
[b1f51f0]154
[fc42b28]155 futex_down(&async_futex);
[936351c1]156 list_append(&call->list, &queued_calls);
[10477601]157
[dcc150cb]158 call->fid = fibril_get_id();
159 fibril_switch(FIBRIL_TO_MANAGER);
160 /* Async futex unlocked by previous call */
[10477601]161
[06502f7d]162 return;
163 }
[10477601]164
[936351c1]165 call->u.callid = callid;
[10477601]166
[8b243f2]167 /* Add call to the list of dispatched calls */
[936351c1]168 list_append(&call->list, &dispatched_calls);
[cdbcf14]169 futex_unlock(&ipc_futex);
[c1d2c9d]170}
171
[10477601]172/** Fast asynchronous call.
[8b243f2]173 *
[3209923]174 * This function can only handle four arguments of payload. It is, however,
175 * faster than the more generic ipc_call_async_slow().
[8b243f2]176 *
177 * Note that this function is a void function.
[10477601]178 *
179 * During normal operation, answering this call will trigger the callback.
180 * In case of fatal error, the callback handler is called with the proper
181 * error code. If the call cannot be temporarily made, it is queued.
[c1d2c9d]182 *
[228e490]183 * @param phoneid Phone handle for the call.
184 * @param imethod Requested interface and method.
185 * @param arg1 Service-defined payload argument.
186 * @param arg2 Service-defined payload argument.
187 * @param arg3 Service-defined payload argument.
188 * @param arg4 Service-defined payload argument.
189 * @param private Argument to be passed to the answer/error callback.
190 * @param callback Answer or error callback.
[c1d2c9d]191 */
[228e490]192void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
[96b02eb9]193 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
[dcc150cb]194 ipc_async_callback_t callback)
[c1d2c9d]195{
[d8b42fb2]196 async_call_t *call = NULL;
[228e490]197
[d8b42fb2]198 if (callback) {
199 call = ipc_prepare_async(private, callback);
200 if (!call)
201 return;
202 }
[228e490]203
[8b243f2]204 /*
[10477601]205 * We need to make sure that we get callid
206 * before another thread accesses the queue again.
[8b243f2]207 */
[10477601]208
[cdbcf14]209 futex_lock(&ipc_futex);
[228e490]210 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
211 imethod, arg1, arg2, arg3, arg4);
212
[b78d0bd]213 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
[d8b42fb2]214 if (!call) {
215 call = ipc_prepare_async(private, callback);
[52d2603]216 if (!call) {
217 futex_unlock(&ipc_futex);
[d8b42fb2]218 return;
[52d2603]219 }
[d8b42fb2]220 }
[10477601]221
[228e490]222 IPC_SET_IMETHOD(call->u.msg.data, imethod);
[c1d2c9d]223 IPC_SET_ARG1(call->u.msg.data, arg1);
224 IPC_SET_ARG2(call->u.msg.data, arg2);
[3209923]225 IPC_SET_ARG3(call->u.msg.data, arg3);
226 IPC_SET_ARG4(call->u.msg.data, arg4);
[10477601]227
[8498915]228 /*
229 * To achieve deterministic behavior, we always zero out the
230 * arguments that are beyond the limits of the fast version.
231 */
[10477601]232
[8498915]233 IPC_SET_ARG5(call->u.msg.data, 0);
[c1d2c9d]234 }
[10477601]235
[dcc150cb]236 ipc_finish_async(callid, phoneid, call);
[c1d2c9d]237}
238
[10477601]239/** Asynchronous call transmitting the entire payload.
[8b243f2]240 *
241 * Note that this function is a void function.
[10477601]242 *
243 * During normal operation, answering this call will trigger the callback.
244 * In case of fatal error, the callback handler is called with the proper
245 * error code. If the call cannot be temporarily made, it is queued.
[8b243f2]246 *
[228e490]247 * @param phoneid Phone handle for the call.
248 * @param imethod Requested interface and method.
249 * @param arg1 Service-defined payload argument.
250 * @param arg2 Service-defined payload argument.
251 * @param arg3 Service-defined payload argument.
252 * @param arg4 Service-defined payload argument.
253 * @param arg5 Service-defined payload argument.
254 * @param private Argument to be passed to the answer/error callback.
255 * @param callback Answer or error callback.
[c1d2c9d]256 */
[228e490]257void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
[96b02eb9]258 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
[dcc150cb]259 ipc_async_callback_t callback)
[c1d2c9d]260{
[10477601]261 async_call_t *call = ipc_prepare_async(private, callback);
[c1d2c9d]262 if (!call)
263 return;
[10477601]264
[228e490]265 IPC_SET_IMETHOD(call->u.msg.data, imethod);
[c1d2c9d]266 IPC_SET_ARG1(call->u.msg.data, arg1);
267 IPC_SET_ARG2(call->u.msg.data, arg2);
268 IPC_SET_ARG3(call->u.msg.data, arg3);
[3209923]269 IPC_SET_ARG4(call->u.msg.data, arg4);
270 IPC_SET_ARG5(call->u.msg.data, arg5);
[10477601]271
[8b243f2]272 /*
[10477601]273 * We need to make sure that we get callid
274 * before another threadaccesses the queue again.
[8b243f2]275 */
[10477601]276
[cdbcf14]277 futex_lock(&ipc_futex);
[10477601]278 ipc_callid_t callid =
279 ipc_call_async_internal(phoneid, &call->u.msg.data);
280
[dcc150cb]281 ipc_finish_async(callid, phoneid, call);
[b419162]282}
283
[10477601]284/** Answer received call (fast version).
[250717cc]285 *
[b74959bd]286 * The fast answer makes use of passing retval and first four arguments in
287 * registers. If you need to return more, use the ipc_answer_slow() instead.
[250717cc]288 *
[10477601]289 * @param callid Hash of the call being answered.
290 * @param retval Return value.
291 * @param arg1 First return argument.
292 * @param arg2 Second return argument.
293 * @param arg3 Third return argument.
294 * @param arg4 Fourth return argument.
295 *
296 * @return Zero on success.
297 * @return Value from @ref errno.h on failure.
[250717cc]298 *
299 */
[96b02eb9]300sysarg_t ipc_answer_fast(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
301 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
[b419162]302{
[b74959bd]303 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
304 arg4);
[b419162]305}
[06502f7d]306
[10477601]307/** Answer received call (entire payload).
308 *
309 * @param callid Hash of the call being answered.
310 * @param retval Return value.
311 * @param arg1 First return argument.
312 * @param arg2 Second return argument.
313 * @param arg3 Third return argument.
314 * @param arg4 Fourth return argument.
315 * @param arg5 Fifth return argument.
[250717cc]316 *
[10477601]317 * @return Zero on success.
318 * @return Value from @ref errno.h on failure.
[250717cc]319 *
320 */
[96b02eb9]321sysarg_t ipc_answer_slow(ipc_callid_t callid, sysarg_t retval, sysarg_t arg1,
322 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5)
[250717cc]323{
[b74959bd]324 ipc_call_t data;
[10477601]325
[b74959bd]326 IPC_SET_RETVAL(data, retval);
327 IPC_SET_ARG1(data, arg1);
328 IPC_SET_ARG2(data, arg2);
329 IPC_SET_ARG3(data, arg3);
330 IPC_SET_ARG4(data, arg4);
331 IPC_SET_ARG5(data, arg5);
[10477601]332
[b74959bd]333 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
[250717cc]334}
335
[10477601]336/** Try to dispatch queued calls from the async queue.
337 *
338 */
339static void dispatch_queued_calls(void)
[936351c1]340{
[8b243f2]341 /** @todo
[10477601]342 * Integrate intelligently ipc_futex so that it is locked during
343 * ipc_call_async_*() until it is added to dispatched_calls.
[fc42b28]344 */
[10477601]345
[fc42b28]346 futex_down(&async_futex);
[10477601]347
[936351c1]348 while (!list_empty(&queued_calls)) {
[10477601]349 async_call_t *call =
[b72efe8]350 list_get_instance(list_first(&queued_calls), async_call_t, list);
[10477601]351 ipc_callid_t callid =
352 ipc_call_async_internal(call->u.msg.phoneid, &call->u.msg.data);
353
354 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY)
[936351c1]355 break;
[10477601]356
[936351c1]357 list_remove(&call->list);
[10477601]358
[fc42b28]359 futex_up(&async_futex);
[10477601]360
[dcc150cb]361 assert(call->fid);
362 fibril_add_ready(call->fid);
[fc42b28]363
[b78d0bd]364 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
[a784a96]365 if (call->callback)
366 call->callback(call->private, ENOENT, NULL);
[10477601]367
[936351c1]368 free(call);
369 } else {
370 call->u.callid = callid;
[10477601]371
[cdbcf14]372 futex_lock(&ipc_futex);
[936351c1]373 list_append(&call->list, &dispatched_calls);
[cdbcf14]374 futex_unlock(&ipc_futex);
[936351c1]375 }
[10477601]376
[fc42b28]377 futex_down(&async_futex);
[936351c1]378 }
[10477601]379
[fc42b28]380 futex_up(&async_futex);
[936351c1]381}
382
[10477601]383/** Handle received answer.
[936351c1]384 *
[8b243f2]385 * Find the hash of the answer and call the answer callback.
[936351c1]386 *
[10477601]387 * The answer has the same hash as the request OR'ed with
388 * the IPC_CALLID_ANSWERED bit.
389 *
390 * @todo Use hash table.
391 *
392 * @param callid Hash of the received answer.
393 * @param data Call data of the answer.
[8b243f2]394 *
[936351c1]395 */
[4c61e60]396static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
[936351c1]397{
398 callid &= ~IPC_CALLID_ANSWERED;
399
[cdbcf14]400 futex_lock(&ipc_futex);
[10477601]401
402 link_t *item;
[b72efe8]403 for (item = dispatched_calls.head.next; item != &dispatched_calls.head;
[8b243f2]404 item = item->next) {
[10477601]405 async_call_t *call =
406 list_get_instance(item, async_call_t, list);
407
[936351c1]408 if (call->u.callid == callid) {
409 list_remove(&call->list);
[10477601]410
[cdbcf14]411 futex_unlock(&ipc_futex);
[10477601]412
[a784a96]413 if (call->callback)
[10477601]414 call->callback(call->private,
[8b243f2]415 IPC_GET_RETVAL(*data), data);
[10477601]416
[a784a96]417 free(call);
[936351c1]418 return;
419 }
420 }
[10477601]421
[cdbcf14]422 futex_unlock(&ipc_futex);
[936351c1]423}
424
[10477601]425/** Wait for first IPC call to come.
426 *
427 * @param call Incoming call storage.
428 * @param usec Timeout in microseconds
429 * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
[8b243f2]430 *
[10477601]431 * @return Hash of the call. Note that certain bits have special
432 * meaning: IPC_CALLID_ANSWERED is set in an answer
433 * and IPC_CALLID_NOTIFICATION is used for notifications.
[b419162]434 *
435 */
[10477601]436ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
437 unsigned int flags)
[b419162]438{
[10477601]439 ipc_callid_t callid =
440 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
441
[80649a91]442 /* Handle received answers */
[fc42b28]443 if (callid & IPC_CALLID_ANSWERED) {
[80649a91]444 handle_answer(callid, call);
[10477601]445 dispatch_queued_calls();
[fc42b28]446 }
[10477601]447
[04a73cdf]448 return callid;
449}
450
[10477601]451/** Interrupt one thread of this task from waiting for IPC.
[04a73cdf]452 *
[10477601]453 */
454void ipc_poke(void)
455{
456 __SYSCALL0(SYS_IPC_POKE);
457}
458
459/** Wait for first IPC call to come.
[8b243f2]460 *
[10477601]461 * Only requests are returned, answers are processed internally.
462 *
463 * @param call Incoming call storage.
464 * @param usec Timeout in microseconds
465 *
466 * @return Hash of the call.
[096ba7a]467 *
[04a73cdf]468 */
[10477601]469ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
[04a73cdf]470{
471 ipc_callid_t callid;
[10477601]472
[04a73cdf]473 do {
[2d22049]474 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
[04a73cdf]475 } while (callid & IPC_CALLID_ANSWERED);
[10477601]476
[04a73cdf]477 return callid;
478}
479
480/** Check if there is an IPC call waiting to be picked up.
481 *
[10477601]482 * Only requests are returned, answers are processed internally.
483 *
484 * @param call Incoming call storage.
485 *
486 * @return Hash of the call.
487 *
[04a73cdf]488 */
489ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
490{
491 ipc_callid_t callid;
[10477601]492
[04a73cdf]493 do {
[8b243f2]494 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
495 SYNCH_FLAGS_NON_BLOCKING);
[06502f7d]496 } while (callid & IPC_CALLID_ANSWERED);
[10477601]497
[b419162]498 return callid;
499}
[5106e98]500
[8b243f2]501/** Hang up a phone.
502 *
[10477601]503 * @param phoneid Handle of the phone to be hung up.
504 *
505 * @return Zero on success or a negative error code.
[8b243f2]506 *
507 */
[7048773]508int ipc_hangup(int phoneid)
509{
510 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
511}
[6180b57]512
[8b243f2]513/** Forward a received call to another destination.
[10477601]514 *
515 * For non-system methods, the old method, arg1 and arg2 are rewritten
516 * by the new values. For system methods, the new method, arg1 and arg2
517 * are written to the old arg1, arg2 and arg3, respectivelly. Calls with
518 * immutable methods are forwarded verbatim.
[8b243f2]519 *
[228e490]520 * @param callid Hash of the call to forward.
521 * @param phoneid Phone handle to use for forwarding.
522 * @param imethod New interface and method for the forwarded call.
523 * @param arg1 New value of the first argument for the forwarded call.
524 * @param arg2 New value of the second argument for the forwarded call.
525 * @param mode Flags specifying mode of the forward operation.
[8b243f2]526 *
[228e490]527 * @return Zero on success or an error code.
[8b243f2]528 *
529 */
[10477601]530int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
531 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
[043dcc27]532{
[228e490]533 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
[90c35436]534 arg2, mode);
[043dcc27]535}
536
[10477601]537int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
[96b02eb9]538 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
[10477601]539 unsigned int mode)
[48daf64]540{
541 ipc_call_t data;
[228e490]542
543 IPC_SET_IMETHOD(data, imethod);
[48daf64]544 IPC_SET_ARG1(data, arg1);
545 IPC_SET_ARG2(data, arg2);
546 IPC_SET_ARG3(data, arg3);
547 IPC_SET_ARG4(data, arg4);
548 IPC_SET_ARG5(data, arg5);
[228e490]549
[10477601]550 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
551 mode);
[48daf64]552}
553
[9a1b20c]554/** Connect to a task specified by id.
[6b10dab]555 *
[9a1b20c]556 */
557int ipc_connect_kbox(task_id_t id)
558{
[6b10dab]559#ifdef __32_BITS__
560 sysarg64_t arg = (sysarg64_t) id;
[9a1b20c]561 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
[6b10dab]562#endif
563
564#ifdef __64_BITS__
565 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
566#endif
[9a1b20c]567}
[6b10dab]568
[fadd381]569/** @}
[b2951e2]570 */
Note: See TracBrowser for help on using the repository browser.