source: mainline/uspace/lib/c/generic/ipc.c@ 0f4532e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0f4532e 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
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 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 }
638 return rc;
639}
640
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
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.
665 *
666 * @return New phone handle on success or a negative error code.
667 *
668 */
669int ipc_connect_me_to(int phoneid, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3)
670{
671 sysarg_t newphid;
672 int res = ipc_call_sync_3_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
673 NULL, NULL, NULL, NULL, &newphid);
674 if (res)
675 return res;
676
677 return newphid;
678}
679
680/** Request new connection (blocking)
681 *
682 * If the connection is not available at the moment, the
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.
690 *
691 * @return New phone handle on success or a negative error code.
692 *
693 */
694int ipc_connect_me_to_blocking(int phoneid, sysarg_t arg1, sysarg_t arg2,
695 sysarg_t arg3)
696{
697 sysarg_t newphid;
698 int res = ipc_call_sync_4_5(phoneid, IPC_M_CONNECT_ME_TO, arg1, arg2, arg3,
699 IPC_FLAG_BLOCKING, NULL, NULL, NULL, NULL, &newphid);
700 if (res)
701 return res;
702
703 return newphid;
704}
705
706/** Hang up a phone.
707 *
708 * @param phoneid Handle of the phone to be hung up.
709 *
710 * @return Zero on success or a negative error code.
711 *
712 */
713int ipc_hangup(int phoneid)
714{
715 return __SYSCALL1(SYS_IPC_HANGUP, phoneid);
716}
717
718/** Forward a received call to another destination.
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.
724 *
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.
731 *
732 * @return Zero on success or an error code.
733 *
734 */
735int ipc_forward_fast(ipc_callid_t callid, int phoneid, sysarg_t imethod,
736 sysarg_t arg1, sysarg_t arg2, unsigned int mode)
737{
738 return __SYSCALL6(SYS_IPC_FORWARD_FAST, callid, phoneid, imethod, arg1,
739 arg2, mode);
740}
741
742int ipc_forward_slow(ipc_callid_t callid, int phoneid, sysarg_t imethod,
743 sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5,
744 unsigned int mode)
745{
746 ipc_call_t data;
747
748 IPC_SET_IMETHOD(data, imethod);
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);
754
755 return __SYSCALL4(SYS_IPC_FORWARD_SLOW, callid, phoneid, (sysarg_t) &data,
756 mode);
757}
758
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.
766 *
767 * @return Zero on success or a negative error code from errno.h.
768 *
769 */
770int ipc_share_in_start(int phoneid, void *dst, size_t size, sysarg_t arg,
771 unsigned int *flags)
772{
773 sysarg_t tmp_flags = 0;
774 int res = ipc_call_sync_3_2(phoneid, IPC_M_SHARE_IN, (sysarg_t) dst,
775 (sysarg_t) size, arg, NULL, &tmp_flags);
776
777 if (flags)
778 *flags = (unsigned int) tmp_flags;
779
780 return res;
781}
782
783/** Wrapper for answering the IPC_M_SHARE_IN calls.
784 *
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.
788 *
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.
794 *
795 */
796int ipc_share_in_finalize(ipc_callid_t callid, void *src, unsigned int flags)
797{
798 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) flags);
799}
800
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.
806 *
807 * @return Zero on success or a negative error code from errno.h.
808 *
809 */
810int ipc_share_out_start(int phoneid, void *src, unsigned int flags)
811{
812 return ipc_call_sync_3_0(phoneid, IPC_M_SHARE_OUT, (sysarg_t) src, 0,
813 (sysarg_t) flags);
814}
815
816/** Wrapper for answering the IPC_M_SHARE_OUT calls.
817 *
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.
821 *
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.
826 *
827 */
828int ipc_share_out_finalize(ipc_callid_t callid, void *dst)
829{
830 return ipc_answer_1(callid, EOK, (sysarg_t) dst);
831}
832
833/** Wrapper for IPC_M_DATA_READ calls.
834 *
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.
840 *
841 */
842int ipc_data_read_start(int phoneid, void *dst, size_t size)
843{
844 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_READ, (sysarg_t) dst,
845 (sysarg_t) size);
846}
847
848/** Wrapper for answering the IPC_M_DATA_READ calls.
849 *
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.
858 *
859 * @return Zero on success or a value from @ref errno.h on failure.
860 *
861 */
862int ipc_data_read_finalize(ipc_callid_t callid, const void *src, size_t size)
863{
864 return ipc_answer_2(callid, EOK, (sysarg_t) src, (sysarg_t) size);
865}
866
867/** Wrapper for IPC_M_DATA_WRITE calls.
868 *
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.
874 *
875 */
876int ipc_data_write_start(int phoneid, const void *src, size_t size)
877{
878 return ipc_call_sync_2_0(phoneid, IPC_M_DATA_WRITE, (sysarg_t) src,
879 (sysarg_t) size);
880}
881
882/** Wrapper for answering the IPC_M_DATA_WRITE calls.
883 *
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.
891 *
892 * @return Zero on success or a value from @ref errno.h on failure.
893 *
894 */
895int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size)
896{
897 return ipc_answer_2(callid, EOK, (sysarg_t) dst, (sysarg_t) size);
898}
899
900/** Connect to a task specified by id.
901 *
902 */
903int ipc_connect_kbox(task_id_t id)
904{
905#ifdef __32_BITS__
906 sysarg64_t arg = (sysarg64_t) id;
907 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg);
908#endif
909
910#ifdef __64_BITS__
911 return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) id);
912#endif
913}
914
915/** @}
916 */
Note: See TracBrowser for help on using the repository browser.