Changeset 8b243f2 in mainline for uspace/libc/generic/ipc.c


Ignore:
Timestamp:
2007-06-17T19:34:36Z (18 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bd72c3e9
Parents:
4680ef5
Message:

Greatly improve comments in the IPC layer.
Now I think I finally start to understand our IPC internals :-)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/libc/generic/ipc.c

    r4680ef5 r8b243f2  
    5252#include <psthread.h>
    5353
    54 /** Structure used for keeping track of sent async msgs
    55  * and queing unsent msgs
    56  *
     54/** Structure used for keeping track of sent asynchronous calls and queing
     55 * unsent calls.
    5756 */
    5857typedef struct {
     
    6766                        int phoneid;
    6867                } msg;
    69         }u;
    70         pstid_t ptid;   /**< Thread waiting for sending this msg */
     68        } u;
     69        pstid_t ptid;   /**< Pseudothread waiting for sending this call. */
    7170} async_call_t;
    7271
    7372LIST_INITIALIZE(dispatched_calls);
    7473
    75 /* queued_calls is protcted by async_futex, because if the
    76  * call cannot be sent into kernel, async framework is used
    77  * automatically
    78  */
    79 LIST_INITIALIZE(queued_calls); /**< List of async calls that were not accepted
    80                                 *   by kernel */
     74/** List of asynchronous calls that were not accepted by kernel.
     75 *
     76 * It is protected by async_futex, because if the call cannot be sent into the
     77 * kernel, the async framework is used automatically.
     78 */
     79LIST_INITIALIZE(queued_calls);
    8180
    8281static atomic_t ipc_futex = FUTEX_INITIALIZER;
    8382
    84 int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1,
    85                   ipcarg_t *result)
     83/** Make a fast synchronous call.
     84 *
     85 * Only one payload argument can be passed using this function. However, this
     86 * function is faster than the generic ipc_call_sync_3().
     87 *
     88 * @param phoneid       Phone handle for the call.
     89 * @param method        Requested method.
     90 * @param arg1          Service-defined payload argument.
     91 * @param result        If non-NULL, the return ARG1 will be stored there.
     92 *
     93 * @return              Negative values represent errors returned by IPC.
     94 *                      Otherwise the RETVAL of the answer is returned.
     95 */
     96int ipc_call_sync(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t *result)
    8697{
    8798        ipc_call_t resdata;
     
    89100       
    90101        callres = __SYSCALL4(SYS_IPC_CALL_SYNC_FAST, phoneid, method, arg1,
    91                              (sysarg_t)&resdata);
     102            (sysarg_t) &resdata);
    92103        if (callres)
    93104                return callres;
     
    97108}
    98109
    99 int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
    100                     ipcarg_t arg2, ipcarg_t arg3,
    101                     ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
     110/** Make a synchronous call transmitting 3 arguments of payload.
     111 *
     112 * @param phoneid       Phone handle for the call.
     113 * @param method        Requested method.
     114 * @param arg1          Service-defined payload argument.
     115 * @param arg2          Service-defined payload argument.
     116 * @param arg3          Service-defined payload argument.
     117 * @param result1       If non-NULL, storage for the first return argument.
     118 * @param result2       If non-NULL, storage for the second return argument.
     119 * @param result3       If non-NULL, storage for the third return argument.
     120 *
     121 * @return              Negative value means IPC error.
     122 *                      Otherwise the RETVAL of the answer.
     123 */
     124int ipc_call_sync_3(int phoneid, ipcarg_t method, ipcarg_t arg1, ipcarg_t arg2,
     125    ipcarg_t arg3, ipcarg_t *result1, ipcarg_t *result2, ipcarg_t *result3)
    102126{
    103127        ipc_call_t data;
     
    109133        IPC_SET_ARG3(data, arg3);
    110134
    111         callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t)&data,
    112                              (sysarg_t)&data);
     135        callres = __SYSCALL3(SYS_IPC_CALL_SYNC, phoneid, (sysarg_t) &data,
     136            (sysarg_t) &data);
    113137        if (callres)
    114138                return callres;
     
    123147}
    124148
    125 /** Syscall to send asynchronous message */
    126 static  ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
    127 {
    128         return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t)data);
    129 }
    130 
    131 /** Prolog to ipc_async_send functions */
    132 static inline async_call_t *ipc_prepare_async(void *private, ipc_async_callback_t callback)
     149/** Syscall to send asynchronous message.
     150 *
     151 * @param phoneid       Phone handle for the call.
     152 * @param data          Call data with the request.
     153 *
     154 * @return              Hash of the call or an error code.
     155 */
     156static ipc_callid_t _ipc_call_async(int phoneid, ipc_call_t *data)
     157{
     158        return __SYSCALL2(SYS_IPC_CALL_ASYNC, phoneid, (sysarg_t) data);
     159}
     160
     161/** Prolog to ipc_call_async_*() functions.
     162 *
     163 * @param private       Argument for the answer/error callback.
     164 * @param callback      Answer/error callback.
     165 *
     166 * @return              New, partially initialized async_call structure or NULL.
     167 */
     168static inline async_call_t *ipc_prepare_async(void *private,
     169    ipc_async_callback_t callback)
    133170{
    134171        async_call_t *call;
     
    146183}
    147184
    148 /** Epilogue of ipc_async_send functions */
    149 static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
    150                                     async_call_t *call, int can_preempt)
     185/** Epilogue of ipc_call_async_*() functions.
     186 *
     187 * @param callid        Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
     188 * @param phoneid       Phone handle through which the call was made.
     189 * @param call          async_call structure returned by ipc_prepare_async().
     190 * @param can_preempt   If non-zero, the current pseudo thread can be preempted
     191 *                      in this call.
     192 */
     193static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
     194    async_call_t *call, int can_preempt)
    151195{
    152196        if (!call) { /* Nothing to do regardless if failed or not */
     
    183227        }
    184228        call->u.callid = callid;
    185         /* Add call to list of dispatched calls */
     229        /* Add call to the list of dispatched calls */
    186230        list_append(&call->list, &dispatched_calls);
    187231        futex_up(&ipc_futex);
     
    189233}
    190234
    191 /** Send asynchronous message
    192  *
    193  * - if fatal error, call callback handler with proper error code
    194  * - if message cannot be temporarily sent, add to queue
     235/** Make a fast asynchronous call.
     236 *
     237 * This function can only handle two arguments of payload. It is, however,
     238 * faster than the more generic ipc_call_async_3().
     239 *
     240 * Note that this function is a void function.
     241 * During normal opertation, answering this call will trigger the callback.
     242 * In case of fatal error, call the callback handler with the proper error code.
     243 * If the call cannot be temporarily made, queue it.
     244 *
     245 * @param phoneid       Phone handle for the call.
     246 * @param method        Requested method.
     247 * @param arg1          Service-defined payload argument.
     248 * @param arg2          Service-defined payload argument.
     249 * @param private       Argument to be passed to the answer/error callback.
     250 * @param callback      Answer or error callback.
     251 * @param can_preempt   If non-zero, the current pseudo thread will be preempted
     252 *                      in case the kernel temporarily refuses to accept more
     253 *                      asynchronous calls.
    195254 */
    196255void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
    197                       ipcarg_t arg2, void *private,
    198                       ipc_async_callback_t callback, int can_preempt)
     256    ipcarg_t arg2, void *private, ipc_async_callback_t callback,
     257    int can_preempt)
    199258{
    200259        async_call_t *call = NULL;
     
    207266        }
    208267
    209         /* We need to make sure that we get callid before
    210          * another thread accesses the queue again */
     268        /*
     269         * We need to make sure that we get callid before another thread
     270         * accesses the queue again.
     271         */
    211272        futex_down(&ipc_futex);
    212         callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1, arg2);
     273        callid = __SYSCALL4(SYS_IPC_CALL_ASYNC_FAST, phoneid, method, arg1,
     274            arg2);
    213275
    214276        if (callid == IPC_CALLRET_TEMPORARY) {
     
    225287}
    226288
    227 /** Send asynchronous message
    228  *
    229  * - if fatal error, call callback handler with proper error code
    230  * - if message cannot be temporarily sent, add to queue
     289/** Make an asynchronous call transmitting the entire payload.
     290 *
     291 * Note that this function is a void function.
     292 * During normal opertation, answering this call will trigger the callback.
     293 * In case of fatal error, call the callback handler with the proper error code.
     294 * If the call cannot be temporarily made, queue it.
     295 *
     296 * @param phoneid       Phone handle for the call.
     297 * @param method        Requested method.
     298 * @param arg1          Service-defined payload argument.
     299 * @param arg2          Service-defined payload argument.
     300 * @param arg3          Service-defined payload argument.
     301 * @param private       Argument to be passed to the answer/error callback.
     302 * @param callback      Answer or error callback.
     303 * @param can_preempt   If non-zero, the current pseudo thread will be preempted
     304 *                      in case the kernel temporarily refuses to accept more
     305 *                      asynchronous calls.
     306 *
    231307 */
    232308void ipc_call_async_3(int phoneid, ipcarg_t method, ipcarg_t arg1,
    233                       ipcarg_t arg2, ipcarg_t arg3, void *private,
    234                       ipc_async_callback_t callback, int can_preempt)
     309    ipcarg_t arg2, ipcarg_t arg3, void *private, ipc_async_callback_t callback,
     310    int can_preempt)
    235311{
    236312        async_call_t *call;
     
    245321        IPC_SET_ARG2(call->u.msg.data, arg2);
    246322        IPC_SET_ARG3(call->u.msg.data, arg3);
    247         /* We need to make sure that we get callid before
    248          * another thread accesses the queue again */
     323        /*
     324         * We need to make sure that we get callid before another thread accesses
     325         * the queue again.
     326         */
    249327        futex_down(&ipc_futex);
    250328        callid = _ipc_call_async(phoneid, &call->u.msg.data);
     
    254332
    255333
    256 /** Send a fast answer to a received call.
    257  *
    258  * The fast answer makes use of passing retval and first two arguments in registers.
    259  * If you need to return more, use the ipc_answer() instead.
    260  *
    261  * @param callid ID of the call being answered.
    262  * @param retval Return value.
    263  * @param arg1 First return argument.
    264  * @param arg2 Second return argument.
    265  *
    266  * @return Zero on success or a value from @ref errno.h on failure.
     334/** Answer a received call - fast version.
     335 *
     336 * The fast answer makes use of passing retval and first two arguments in
     337 * registers. If you need to return more, use the ipc_answer() instead.
     338 *
     339 * @param callid        Hash of the call being answered.
     340 * @param retval        Return value.
     341 * @param arg1          First return argument.
     342 * @param arg2          Second return argument.
     343 *
     344 * @return              Zero on success or a value from @ref errno.h on failure.
    267345 */
    268346ipcarg_t ipc_answer_fast(ipc_callid_t callid, ipcarg_t retval, ipcarg_t arg1,
    269                 ipcarg_t arg2)
     347    ipcarg_t arg2)
    270348{
    271349        return __SYSCALL4(SYS_IPC_ANSWER_FAST, callid, retval, arg1, arg2);
    272350}
    273351
    274 /** Send a full answer to a received call.
    275  *
    276  * @param callid ID of the call being answered.
    277  * @param call Call data. Must be already initialized by the responder.
    278  *
    279  * @return Zero on success or a value from @ref errno.h on failure.
     352/** Answer a received call - full version.
     353 *
     354 * @param callid        Hash of the call being answered.
     355 * @param call          Call structure with the answer.
     356 *                      Must be already initialized by the responder.
     357 *
     358 * @return              Zero on success or a value from @ref errno.h on failure.
    280359 */
    281360ipcarg_t ipc_answer(ipc_callid_t callid, ipc_call_t *call)
     
    285364
    286365
    287 /** Try to dispatch queed calls from async queue */
     366/** Try to dispatch queued calls from the async queue. */
    288367static void try_dispatch_queued_calls(void)
    289368{
     
    291370        ipc_callid_t callid;
    292371
    293         /* TODO: integrate intelligently ipc_futex, so that it
    294          * is locked during ipc_call_async, until it is added
    295          * to dispatched_calls
     372        /** @todo
     373         * Integrate intelligently ipc_futex, so that it is locked during
     374         * ipc_call_async_*(), until it is added to dispatched_calls.
    296375         */
    297376        futex_down(&async_futex);
    298377        while (!list_empty(&queued_calls)) {
    299                 call = list_get_instance(queued_calls.next, async_call_t,
    300                                          list);
    301 
    302                 callid = _ipc_call_async(call->u.msg.phoneid,
    303                                          &call->u.msg.data);
     378                call = list_get_instance(queued_calls.next, async_call_t, list);
     379                callid = _ipc_call_async(call->u.msg.phoneid, &call->u.msg.data);
    304380                if (callid == IPC_CALLRET_TEMPORARY) {
    305381                        break;
     
    326402}
    327403
    328 /** Handle received answer
    329  *
    330  * TODO: Make it use hash table
    331  *
    332  * @param callid Callid (with first bit set) of the answered call
     404/** Handle a received answer.
     405 *
     406 * Find the hash of the answer and call the answer callback.
     407 *
     408 * @todo Make it use hash table.
     409 *
     410 * @param callid        Hash of the received answer.
     411 *                      The answer has the same hash as the request OR'ed with
     412 *                      the IPC_CALLID_ANSWERED bit.
     413 * @param data          Call data of the answer.
    333414 */
    334415static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
     
    341422        futex_down(&ipc_futex);
    342423        for (item = dispatched_calls.next; item != &dispatched_calls;
    343              item = item->next) {
     424            item = item->next) {
    344425                call = list_get_instance(item, async_call_t, list);
    345426                if (call->u.callid == callid) {
     
    348429                        if (call->callback)
    349430                                call->callback(call->private,
    350                                                IPC_GET_RETVAL(*data),
    351                                                data);
     431                                    IPC_GET_RETVAL(*data), data);
    352432                        free(call);
    353433                        return;
     
    355435        }
    356436        futex_up(&ipc_futex);
    357         /* We may get here after async_msg, which doesn't register any callback */
    358 }
    359 
    360 
    361 /** One cycle of ipc wait for call call
    362  *
    363  * - dispatch ASYNC reoutines in the background
    364  * @param call Space where the message is stored
    365  * @param usec Timeout in microseconds
    366  * @param flags Flags passed to SYS_IPC_WAIT (blocking, nonblocking)
    367  * @return Callid of the answer.
     437}
     438
     439
     440/** Wait for a first call to come.
     441 *
     442 * @param call          Storage where the incoming call data will be stored.
     443 * @param usec          Timeout in microseconds
     444 * @param flags         Flags passed to SYS_IPC_WAIT (blocking, nonblocking).
     445 *
     446 * @return              Hash of the call. Note that certain bits have special
     447 *                      meaning. IPC_CALLID_ANSWERED will be set in an answer
     448 *                      and IPC_CALLID_NOTIFICATION is used for notifications.
     449 *                     
    368450 */
    369451ipc_callid_t ipc_wait_cycle(ipc_call_t *call, uint32_t usec, int flags)
     
    383465/** Wait some time for an IPC call.
    384466 *
    385  * - dispatch ASYNC reoutines in the background
    386  *
    387  * @param call Space where the message is stored
    388  * @param usec Timeout in microseconds.
    389  * @return Callid of the answer.
     467 * The call will return after an answer is received.
     468 *
     469 * @param call          Storage where the incoming call data will be stored.
     470 * @param usec          Timeout in microseconds.
     471 *
     472 * @return              Hash of the answer.
    390473 */
    391474ipc_callid_t ipc_wait_for_call_timeout(ipc_call_t *call, uint32_t usec)
     
    402485/** Check if there is an IPC call waiting to be picked up.
    403486 *
    404  * - dispatch ASYNC reoutines in the background
    405  *
    406  * @param call Space where the message is stored
    407  * @return Callid of the answer.
     487 * @param call          Storage where the incoming call will be stored.
     488 * @return              Hash of the answer.
    408489 */
    409490ipc_callid_t ipc_trywait_for_call(ipc_call_t *call)
     
    412493
    413494        do {
    414                 callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NON_BLOCKING);
     495                callid = ipc_wait_cycle(call, SYNCH_NO_TIMEOUT,
     496                    SYNCH_FLAGS_NON_BLOCKING);
    415497        } while (callid & IPC_CALLID_ANSWERED);
    416498
     
    420502/** Ask destination to do a callback connection.
    421503 *
    422  * @param phoneid       Phone ID used for contacting the other side.
     504 * @param phoneid       Phone handle used for contacting the other side.
     505 * @param arg1          Service-defined argument.
     506 * @param arg2          Service-defined argument.
     507 * @param phonehash     Storage where the library will store an opaque
     508 *                      identifier of the phone that will be used for incoming
     509 *                      calls. This identifier can be used for connection
     510 *                      tracking.
     511 *
     512 * @return              Zero on success or a negative error code.
     513 */
     514int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
     515{
     516        return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0,
     517            phonehash);
     518}
     519
     520/** Ask through phone for a new connection to some service.
     521 *
     522 * @param phoneid       Phone handle used for contacting the other side.
    423523 * @param arg1          User defined argument.
    424524 * @param arg2          User defined argument.
    425  * @param phonehash     Pointer to a place where the library will store an opaque
    426  *                      identifier of the phone that will be used for incoming
    427  *                      calls.
    428  * @return Zero on success or a negative error code.
    429  */
    430 int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phonehash)
    431 {
    432         return ipc_call_sync_3(phoneid, IPC_M_CONNECT_TO_ME, arg1, arg2, 0, 0, 0,
    433             phonehash);
    434 }
    435 
    436 /** Ask through phone for a new connection to some service.
    437  *
    438  * @param phoneid       Phone ID used for contacting the other side.
    439  * @param arg1          User defined argument.
    440  * @param arg2          User defined argument.
    441  *
    442  * @return New phone ID on success or a negative error code.
     525 *
     526 * @return              New phone handle on success or a negative error code.
    443527 */
    444528int ipc_connect_me_to(int phoneid, int arg1, int arg2)
     
    454538}
    455539
    456 /* Hang up specified phone */
     540/** Hang up a phone.
     541 *
     542 * @param phoneid       Handle of the phone to be hung up.
     543 *
     544 * @return              Zero on success or a negative error code.
     545 */
    457546int ipc_hangup(int phoneid)
    458547{
     
    462551/** Register IRQ notification.
    463552 *
    464  * @param inr IRQ number.
    465  * @param devno Device number of the device generating inr.
    466  * @param method Use this method for notifying me.
    467  * @param ucode Top-half pseudocode handler.
    468  *
    469  * @return Value returned by the kernel.
     553 * @param inr           IRQ number.
     554 * @param devno         Device number of the device generating inr.
     555 * @param method        Use this method for notifying me.
     556 * @param ucode         Top-half pseudocode handler.
     557 *
     558 * @return              Value returned by the kernel.
    470559 */
    471560int ipc_register_irq(int inr, int devno, int method, irq_code_t *ucode)
    472561{
    473         return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method, (sysarg_t) ucode);
     562        return __SYSCALL4(SYS_IPC_REGISTER_IRQ, inr, devno, method,
     563            (sysarg_t) ucode);
    474564}
    475565
    476566/** Unregister IRQ notification.
    477567 *
    478  * @param inr IRQ number.
    479  * @param devno Device number of the device generating inr.
    480  *
    481  * @return Value returned by the kernel.
     568 * @param inr           IRQ number.
     569 * @param devno         Device number of the device generating inr.
     570 *
     571 * @return              Value returned by the kernel.
    482572 */
    483573int ipc_unregister_irq(int inr, int devno)
     
    486576}
    487577
     578/** Forward a received call to another destination.
     579 *
     580 * @param callid        Hash of the call to forward.
     581 * @param phoneid       Phone handle to use for forwarding.
     582 * @param method        New method for the forwarded call.
     583 * @param arg1          New value of the first argument for the forwarded call.
     584 *
     585 * @return              Zero on success or an error code.
     586 *
     587 * For non-system methods, the old method and arg1 are rewritten by the new
     588 * values. For system methods, the new method and arg1 are written to the old
     589 * arg1 and arg2, respectivelly.
     590 */
    488591int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
    489592{
Note: See TracChangeset for help on using the changeset viewer.