Subversion Repositories HelenOS

Rev

Rev 2490 | Rev 2531 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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