source: mainline/uspace/lib/c/generic/ipc.c@ 16f9782

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

Fix leftover use of task hash in ipc_connect_to_me().

  • Property mode set to 100644
File size: 25.9 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
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.
27 */
28
29/** @addtogroup libc
30 * @{
31 * @}
32 */
33
34/** @addtogroup libcipc IPC
35 * @brief HelenOS uspace IPC
36 * @{
37 * @ingroup libc
38 */
39/** @file
40 */
41
42#include <ipc/ipc.h>
43#include <libc.h>
44#include <malloc.h>
45#include <errno.h>
46#include <adt/list.h>
47#include <futex.h>
48#include <fibril.h>
49#include <macros.h>
50
51/**
52 * Structures of this type are used for keeping track
53 * of sent asynchronous calls and queing unsent calls.
54 */
55typedef struct {
56 link_t list;
57
58 ipc_async_callback_t callback;
59 void *private;
60
61 union {
62 ipc_callid_t callid;
63 struct {
64 ipc_call_t data;
65 int phoneid;
66 } msg;
67 } u;
68
69 /** Fibril waiting for sending this call. */
70 fid_t fid;
71} async_call_t;
72
73LIST_INITIALIZE(dispatched_calls);
74
75/** List of asynchronous calls that were not accepted by kernel.
76 *
77 * Protected by async_futex, because if the call is not accepted
78 * by the kernel, the async framework is used automatically.
79 *
80 */
81LIST_INITIALIZE(queued_calls);
82
83static atomic_t ipc_futex = FUTEX_INITIALIZER;
84
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)
109{
110 ipc_call_t resdata;
111 int callres = __SYSCALL6(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
112 arg2, arg3, (sysarg_t) &resdata);
113 if (callres)
114 return callres;
115
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);
126
127 return IPC_GET_RETVAL(resdata);
128}
129
130/** Synchronous call transmitting 5 arguments of payload.
131 *
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 *
145 * @return Negative values representing IPC errors.
146 * @return Otherwise the RETVAL of the answer.
147 *
148 */
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)
153{
154 ipc_call_t data;
155
156 IPC_SET_IMETHOD(data, imethod);
157 IPC_SET_ARG1(data, arg1);
158 IPC_SET_ARG2(data, arg2);
159 IPC_SET_ARG3(data, arg3);
160 IPC_SET_ARG4(data, arg4);
161 IPC_SET_ARG5(data, arg5);
162
163 int callres = __SYSCALL3(SYS_IPC_CALL_SYNC_SLOW, phoneid,
164 (sysarg_t) &data, (sysarg_t) &data);
165 if (callres)
166 return callres;
167
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);
174 if (result4)
175 *result4 = IPC_GET_ARG4(data);
176 if (result5)
177 *result5 = IPC_GET_ARG5(data);
178
179 return IPC_GET_RETVAL(data);
180}
181
182/** Send asynchronous message via syscall.
183 *
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.
188 *
189 */
190static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
191{
192 return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
193}
194
195/** Prolog for ipc_call_async_*() functions.
196 *
197 * @param private Argument for the answer/error callback.
198 * @param callback Answer/error callback.
199 *
200 * @return New, partially initialized async_call structure or NULL.
201 *
202 */
203static inline async_call_t *ipc_prepare_async(void *private,
204 ipc_async_callback_t callback)
205{
206 async_call_t *call =
207 (async_call_t *) malloc(sizeof(async_call_t));
208 if (!call) {
209 if (callback)
210 callback(private, ENOMEM, NULL);
211
212 return NULL;
213 }
214
215 call->callback = callback;
216 call->private = private;
217
218 return call;
219}
220
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.
228 *
229 */
230static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
231 async_call_t *call, bool can_preempt)
232{
233 if (!call) {
234 /* Nothing to do regardless if failed or not */
235 futex_up(&ipc_futex);
236 return;
237 }
238
239 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
240 futex_up(&ipc_futex);
241
242 /* Call asynchronous handler with error code */
243 if (call->callback)
244 call->callback(call->private, ENOENT, NULL);
245
246 free(call);
247 return;
248 }
249
250 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
251 futex_up(&ipc_futex);
252
253 call->u.msg.phoneid = phoneid;
254
255 futex_down(&async_futex);
256 list_append(&call->list, &queued_calls);
257
258 if (can_preempt) {
259 call->fid = fibril_get_id();
260 fibril_switch(FIBRIL_TO_MANAGER);
261 /* Async futex unlocked by previous call */
262 } else {
263 call->fid = 0;
264 futex_up(&async_futex);
265 }
266
267 return;
268 }
269
270 call->u.callid = callid;
271
272 /* Add call to the list of dispatched calls */
273 list_append(&call->list, &dispatched_calls);
274 futex_up(&ipc_futex);
275}
276
277/** Fast asynchronous call.
278 *
279 * This function can only handle four arguments of payload. It is, however,
280 * faster than the more generic ipc_call_async_slow().
281 *
282 * Note that this function is a void function.
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.
287 *
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.
296 * @param can_preempt If true, the current fibril will be preempted in
297 * case the kernel temporarily refuses to accept more
298 * asynchronous calls.
299 *
300 */
301void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
302 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
303 ipc_async_callback_t callback, bool can_preempt)
304{
305 async_call_t *call = NULL;
306
307 if (callback) {
308 call = ipc_prepare_async(private, callback);
309 if (!call)
310 return;
311 }
312
313 /*
314 * We need to make sure that we get callid
315 * before another thread accesses the queue again.
316 */
317
318 futex_down(&ipc_futex);
319 ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
320 imethod, arg1, arg2, arg3, arg4);
321
322 if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
323 if (!call) {
324 call = ipc_prepare_async(private, callback);
325 if (!call)
326 return;
327 }
328
329 IPC_SET_IMETHOD(call->u.msg.data, imethod);
330 IPC_SET_ARG1(call->u.msg.data, arg1);
331 IPC_SET_ARG2(call->u.msg.data, arg2);
332 IPC_SET_ARG3(call->u.msg.data, arg3);
333 IPC_SET_ARG4(call->u.msg.data, arg4);
334
335 /*
336 * To achieve deterministic behavior, we always zero out the
337 * arguments that are beyond the limits of the fast version.
338 */
339
340 IPC_SET_ARG5(call->u.msg.data, 0);
341 }
342
343 ipc_finish_async(callid, phoneid, call, can_preempt);
344}
345
346/** Asynchronous call transmitting the entire payload.
347 *
348 * Note that this function is a void function.
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.
353 *
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.
363 * @param can_preempt If true, the current fibril will be preempted in
364 * case the kernel temporarily refuses to accept more
365 * asynchronous calls.
366 *
367 */
368void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
369 sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
370 ipc_async_callback_t callback, bool can_preempt)
371{
372 async_call_t *call = ipc_prepare_async(private, callback);
373 if (!call)
374 return;
375
376 IPC_SET_IMETHOD(call->u.msg.data, imethod);
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);
380 IPC_SET_ARG4(call->u.msg.data, arg4);
381 IPC_SET_ARG5(call->u.msg.data, arg5);
382
383 /*
384 * We need to make sure that we get callid
385 * before another threadaccesses the queue again.
386 */
387
388 futex_down(&ipc_futex);
389 ipc_callid_t callid =
390 ipc_call_async_internal(phoneid, &call->u.msg.data);
391
392 ipc_finish_async(callid, phoneid, call, can_preempt);
393}
394
395/** Answer received call (fast version).
396 *
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.
399 *
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.
409 *
410 */
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)
413{
414 return __SYSCALL6(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2, arg3,
415 arg4);
416}
417
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.
427 *
428 * @return Zero on success.
429 * @return Value from @ref errno.h on failure.
430 *
431 */
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)
434{
435 ipc_call_t data;
436
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);
443
444 return __SYSCALL2(SYS_IPC_ANSWER_SLOW, callid, (sysarg_t) &data);
445}
446
447/** Try to dispatch queued calls from the async queue.
448 *
449 */
450static void dispatch_queued_calls(void)
451{
452 /** @todo
453 * Integrate intelligently ipc_futex so that it is locked during
454 * ipc_call_async_*() until it is added to dispatched_calls.
455 */
456
457 futex_down(&async_futex);
458
459 while (!list_empty(&queued_calls)) {
460 async_call_t *call =
461 list_get_instance(list_first(&queued_calls), async_call_t, list);
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)
466 break;
467
468 list_remove(&call->list);
469
470 futex_up(&async_futex);
471
472 if (call->fid)
473 fibril_add_ready(call->fid);
474
475 if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
476 if (call->callback)
477 call->callback(call->private, ENOENT, NULL);
478
479 free(call);
480 } else {
481 call->u.callid = callid;
482
483 futex_down(&ipc_futex);
484 list_append(&call->list, &dispatched_calls);
485 futex_up(&ipc_futex);
486 }
487
488 futex_down(&async_futex);
489 }
490
491 futex_up(&async_futex);
492}
493
494/** Handle received answer.
495 *
496 * Find the hash of the answer and call the answer callback.
497 *
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.
505 *
506 */
507static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
508{
509 callid &= ~IPC_CALLID_ANSWERED;
510
511 futex_down(&ipc_futex);
512
513 link_t *item;
514 for (item = dispatched_calls.head.next; item != &dispatched_calls.head;
515 item = item->next) {
516 async_call_t *call =
517 list_get_instance(item, async_call_t, list);
518
519 if (call->u.callid == callid) {
520 list_remove(&call->list);
521
522 futex_up(&ipc_futex);
523
524 if (call->callback)
525 call->callback(call->private,
526 IPC_GET_RETVAL(*data), data);
527
528 free(call);
529 return;
530 }
531 }
532
533 futex_up(&ipc_futex);
534}
535
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).
541 *
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.
545 *
546 */
547ipc_callid_t ipc_wait_cycle(ipc_call_t *call, sysarg_t usec,
548 unsigned int flags)
549{
550 ipc_callid_t callid =
551 __SYSCALL3(SYS_IPC_WAIT, (sysarg_t) call, usec, flags);
552
553 /* Handle received answers */
554 if (callid & IPC_CALLID_ANSWERED) {
555 handle_answer(callid, call);
556 dispatch_queued_calls();
557 }
558
559 return callid;
560}
561
562/** Interrupt one thread of this task from waiting for IPC.
563 *
564 */
565void ipc_poke(void)
566{
567 __SYSCALL0(SYS_IPC_POKE);
568}
569
570/** Wait for first IPC call to come.
571 *
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.
578 *
579 */
580ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, sysarg_t usec)
581{
582 ipc_callid_t callid;
583
584 do {
585 callid = ipc_wait_cycle(call, usec, SYNCH_FLAGS_NONE);
586 } while (callid & IPC_CALLID_ANSWERED);
587
588 return callid;
589}
590
591/** Check if there is an IPC call waiting to be picked up.
592 *
593 * Only requests are returned, answers are processed internally.
594 *
595 * @param call Incoming call storage.
596 *
597 * @return Hash of the call.
598 *
599 */
600ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
601{
602 ipc_callid_t callid;
603
604 do {
605 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
606 SYNCH_FLAGS_NON_BLOCKING);
607 } while (callid & IPC_CALLID_ANSWERED);
608
609 return callid;
610}
611
612/** Request callback connection.
613 *
614 * The @a task_id and @a phonehash identifiers returned
615 * by the kernel can be used for connection tracking.
616 *
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.
621 * @param task_id Identifier of the client task.
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.
626 *
627 */
628int ipc_connect_to_me(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
629 task_id_t *task_id, sysarg_t *phonehash)
630{
631 sysarg_t task_id_lo = 0;
632 sysarg_t task_id_hi = 0;
633 int rc;
634
635 rc = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
636 NULL, NULL, &task_id_lo, &task_id_hi, phonehash);
637
638 *task_id = (task_id_t) MERGE_LOUP32(task_id_lo, task_id_hi);
639 return rc;
640}
641
642/** Request cloned connection.
643 *
644 * @param phoneid Phone handle used for contacting the other side.
645 *
646 * @return Cloned phone handle on success or a negative error code.
647 *
648 */
649int ipc_connect_me(int phoneid)
650{
651 sysarg_t newphid;
652 int res = ipc_call_sync_0_5(phoneid, IPC_M_CONNECT_ME, NULL, NULL,
653 NULL, NULL, &newphid);
654 if (res)
655 return res;
656
657 return newphid;
658}
659
660/** Request new connection.
661 *
662 * @param phoneid Phone handle used for contacting the other side.
663 * @param arg1 User defined argument.
664 * @param arg2 User defined argument.
665 * @param arg3 User defined argument.
666 *
667 * @return New phone handle on success or a negative error code.
668 *
669 */
670int ipc_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
671{
672 sysarg_t newphid;
673 int res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
674 NULL, NULL, NULL, NULL, &newphid);
675 if (res)
676 return res;
677
678 return newphid;
679}
680
681/** Request new connection (blocking)
682 *
683 * If the connection is not available at the moment, the
684 * call should block. This has to be, however, implemented
685 * on the server side.
686 *
687 * @param phoneid Phone handle used for contacting the other side.
688 * @param arg1 User defined argument.
689 * @param arg2 User defined argument.
690 * @param arg3 User defined argument.
691 *
692 * @return New phone handle on success or a negative error code.
693 *
694 */
695int ipc_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
696 sysarg_t arg3)
697{
698 sysarg_t newphid;
699 int res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
700 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
701 if (res)
702 return res;
703
704 return newphid;
705}
706
707/** Hang up a phone.
708 *
709 * @param phoneid Handle of the phone to be hung up.
710 *
711 * @return Zero on success or a negative error code.
712 *
713 */
714int ipc_hangup(int phoneid)
715{
716 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
717}
718
719/** Forward a received call to another destination.
720 *
721 * For non-system methods, the old method, arg1 and arg2 are rewritten
722 * by the new values. For system methods, the new method, arg1 and arg2
723 * are written to the old arg1, arg2 and arg3, respectivelly. Calls with
724 * immutable methods are forwarded verbatim.
725 *
726 * @param callid Hash of the call to forward.
727 * @param phoneid Phone handle to use for forwarding.
728 * @param imethod New interface and method for the forwarded call.
729 * @param arg1 New value of the first argument for the forwarded call.
730 * @param arg2 New value of the second argument for the forwarded call.
731 * @param mode Flags specifying mode of the forward operation.
732 *
733 * @return Zero on success or an error code.
734 *
735 */
736int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
737 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
738{
739 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
740 arg2, mode);
741}
742
743int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
744 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
745 unsigned int mode)
746{
747 ipc_call_t data;
748
749 IPC_SET_IMETHOD(data, imethod);
750 IPC_SET_ARG1(data, arg1);
751 IPC_SET_ARG2(data, arg2);
752 IPC_SET_ARG3(data, arg3);
753 IPC_SET_ARG4(data, arg4);
754 IPC_SET_ARG5(data, arg5);
755
756 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
757 mode);
758}
759
760/** Wrapper for IPC_M_SHARE_IN calls.
761 *
762 * @param phoneid Phone that will be used to contact the receiving side.
763 * @param dst Destination address space area base.
764 * @param size Size of the destination address space area.
765 * @param arg User defined argument.
766 * @param flags Storage for received flags. Can be NULL.
767 *
768 * @return Zero on success or a negative error code from errno.h.
769 *
770 */
771int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
772 unsigned int *flags)
773{
774 sysarg_t tmp_flags = 0;
775 int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
776 (sysarg_t) size, arg, NULL, &tmp_flags);
777
778 if (flags)
779 *flags = (unsigned int) tmp_flags;
780
781 return res;
782}
783
784/** Wrapper for answering the IPC_M_SHARE_IN calls.
785 *
786 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
787 * calls so that the user doesn't have to remember the meaning of each
788 * IPC argument.
789 *
790 * @param callid Hash of the IPC_M_DATA_READ call to answer.
791 * @param src Source address space base.
792 * @param flags Flags to be used for sharing. Bits can be only cleared.
793 *
794 * @return Zero on success or a value from @ref errno.h on failure.
795 *
796 */
797int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
798{
799 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
800}
801
802/** Wrapper for IPC_M_SHARE_OUT calls.
803 *
804 * @param phoneid Phone that will be used to contact the receiving side.
805 * @param src Source address space area base address.
806 * @param flags Flags to be used for sharing. Bits can be only cleared.
807 *
808 * @return Zero on success or a negative error code from errno.h.
809 *
810 */
811int ipc_share_out_start(int phoneid, void *src, unsigned int flags)
812{
813 return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
814 (sysarg_t) flags);
815}
816
817/** Wrapper for answering the IPC_M_SHARE_OUT calls.
818 *
819 * This wrapper only makes it more comfortable to answer IPC_M_SHARE_OUT
820 * calls so that the user doesn't have to remember the meaning of each
821 * IPC argument.
822 *
823 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.
824 * @param dst Destination address space area base address.
825 *
826 * @return Zero on success or a value from @ref errno.h on failure.
827 *
828 */
829int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
830{
831 return ipc_answer_1(callid, EOK, (sysarg_t) dst);
832}
833
834/** Wrapper for IPC_M_DATA_READ calls.
835 *
836 * @param phoneid Phone that will be used to contact the receiving side.
837 * @param dst Address of the beginning of the destination buffer.
838 * @param size Size of the destination buffer.
839 *
840 * @return Zero on success or a negative error code from errno.h.
841 *
842 */
843int ipc_data_read_start(int phoneid, void *dst, size_t size)
844{
845 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
846 (sysarg_t) size);
847}
848
849/** Wrapper for answering the IPC_M_DATA_READ calls.
850 *
851 * This wrapper only makes it more comfortable to answer IPC_M_DATA_READ
852 * calls so that the user doesn't have to remember the meaning of each
853 * IPC argument.
854 *
855 * @param callid Hash of the IPC_M_DATA_READ call to answer.
856 * @param src Source address for the IPC_M_DATA_READ call.
857 * @param size Size for the IPC_M_DATA_READ call. Can be smaller than
858 * the maximum size announced by the sender.
859 *
860 * @return Zero on success or a value from @ref errno.h on failure.
861 *
862 */
863int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
864{
865 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size);
866}
867
868/** Wrapper for IPC_M_DATA_WRITE calls.
869 *
870 * @param phoneid Phone that will be used to contact the receiving side.
871 * @param src Address of the beginning of the source buffer.
872 * @param size Size of the source buffer.
873 *
874 * @return Zero on success or a negative error code from errno.h.
875 *
876 */
877int ipc_data_write_start(int phoneid, const void *src, size_t size)
878{
879 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
880 (sysarg_t) size);
881}
882
883/** Wrapper for answering the IPC_M_DATA_WRITE calls.
884 *
885 * This wrapper only makes it more comfortable to answer IPC_M_DATA_WRITE
886 * calls so that the user doesn't have to remember the meaning of each
887 * IPC argument.
888 *
889 * @param callid Hash of the IPC_M_DATA_WRITE call to answer.
890 * @param dst Final destination address for the IPC_M_DATA_WRITE call.
891 * @param size Final size for the IPC_M_DATA_WRITE call.
892 *
893 * @return Zero on success or a value from @ref errno.h on failure.
894 *
895 */
896int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
897{
898 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size);
899}
900
901/** Connect to a task specified by id.
902 *
903 */
904int ipc_connect_kbox(task_id_t id)
905{
906#ifdef __32_BITS__
907 sysarg64_t arg = (sysarg64_t) id;
908 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
909#endif
910
911#ifdef __64_BITS__
912 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
913#endif
914}
915
916/** @}
917 */
Note: See TracBrowser for help on using the repository browser.