Ignore:
File:
1 edited

Legend:

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

    rc170438 rd7978525  
    8181LIST_INITIALIZE(queued_calls);
    8282
    83 static futex_t ipc_futex = FUTEX_INITIALIZER;
     83static atomic_t ipc_futex = FUTEX_INITIALIZER;
    8484
    8585/** Send asynchronous message via syscall.
     
    9696}
    9797
    98 /** Prologue for ipc_call_async_*() functions.
     98/** Prolog for ipc_call_async_*() functions.
    9999 *
    100100 * @param private  Argument for the answer/error callback.
     
    122122}
    123123
    124 /** Epilogue for ipc_call_async_*() functions.
     124/** Epilog for ipc_call_async_*() functions.
    125125 *
    126126 * @param callid      Value returned by the SYS_IPC_CALL_ASYNC_* syscall.
    127127 * @param phoneid     Phone handle through which the call was made.
    128128 * @param call        Structure returned by ipc_prepare_async().
     129 * @param can_preempt If true, the current fibril can be preempted
     130 *                    in this call.
     131 *
    129132 */
    130133static inline void ipc_finish_async(ipc_callid_t callid, int phoneid,
    131     async_call_t *call)
     134    async_call_t *call, bool can_preempt)
    132135{
    133136        if (!call) {
    134137                /* Nothing to do regardless if failed or not */
    135                 futex_unlock(&ipc_futex);
     138                futex_up(&ipc_futex);
    136139                return;
    137140        }
    138141       
    139142        if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
    140                 futex_unlock(&ipc_futex);
     143                futex_up(&ipc_futex);
    141144               
    142145                /* Call asynchronous handler with error code */
     
    149152       
    150153        if (callid == (ipc_callid_t) IPC_CALLRET_TEMPORARY) {
    151                 futex_unlock(&ipc_futex);
     154                futex_up(&ipc_futex);
    152155               
    153156                call->u.msg.phoneid = phoneid;
     
    156159                list_append(&call->list, &queued_calls);
    157160               
    158                 call->fid = fibril_get_id();
    159                 fibril_switch(FIBRIL_TO_MANAGER);
    160                 /* Async futex unlocked by previous call */
     161                if (can_preempt) {
     162                        call->fid = fibril_get_id();
     163                        fibril_switch(FIBRIL_TO_MANAGER);
     164                        /* Async futex unlocked by previous call */
     165                } else {
     166                        call->fid = 0;
     167                        futex_up(&async_futex);
     168                }
    161169               
    162170                return;
     
    167175        /* Add call to the list of dispatched calls */
    168176        list_append(&call->list, &dispatched_calls);
    169         futex_unlock(&ipc_futex);
     177        futex_up(&ipc_futex);
    170178}
    171179
     
    189197 * @param private     Argument to be passed to the answer/error callback.
    190198 * @param callback    Answer or error callback.
     199 * @param can_preempt If true, the current fibril will be preempted in
     200 *                    case the kernel temporarily refuses to accept more
     201 *                    asynchronous calls.
     202 *
    191203 */
    192204void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
    193205    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
    194     ipc_async_callback_t callback)
     206    ipc_async_callback_t callback, bool can_preempt)
    195207{
    196208        async_call_t *call = NULL;
     
    207219         */
    208220       
    209         futex_lock(&ipc_futex);
     221        futex_down(&ipc_futex);
    210222        ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
    211223            imethod, arg1, arg2, arg3, arg4);
     
    214226                if (!call) {
    215227                        call = ipc_prepare_async(private, callback);
    216                         if (!call) {
    217                                 futex_unlock(&ipc_futex);
     228                        if (!call)
    218229                                return;
    219                         }
    220230                }
    221231               
     
    234244        }
    235245       
    236         ipc_finish_async(callid, phoneid, call);
     246        ipc_finish_async(callid, phoneid, call, can_preempt);
    237247}
    238248
     
    254264 * @param private     Argument to be passed to the answer/error callback.
    255265 * @param callback    Answer or error callback.
     266 * @param can_preempt If true, the current fibril will be preempted in
     267 *                    case the kernel temporarily refuses to accept more
     268 *                    asynchronous calls.
     269 *
    256270 */
    257271void ipc_call_async_slow(int phoneid, sysarg_t imethod, sysarg_t arg1,
    258272    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, sysarg_t arg5, void *private,
    259     ipc_async_callback_t callback)
     273    ipc_async_callback_t callback, bool can_preempt)
    260274{
    261275        async_call_t *call = ipc_prepare_async(private, callback);
     
    275289         */
    276290       
    277         futex_lock(&ipc_futex);
     291        futex_down(&ipc_futex);
    278292        ipc_callid_t callid =
    279293            ipc_call_async_internal(phoneid, &call->u.msg.data);
    280294       
    281         ipc_finish_async(callid, phoneid, call);
     295        ipc_finish_async(callid, phoneid, call, can_preempt);
    282296}
    283297
     
    359373                futex_up(&async_futex);
    360374               
    361                 assert(call->fid);
    362                 fibril_add_ready(call->fid);
     375                if (call->fid)
     376                        fibril_add_ready(call->fid);
    363377               
    364378                if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
     
    370384                        call->u.callid = callid;
    371385                       
    372                         futex_lock(&ipc_futex);
     386                        futex_down(&ipc_futex);
    373387                        list_append(&call->list, &dispatched_calls);
    374                         futex_unlock(&ipc_futex);
     388                        futex_up(&ipc_futex);
    375389                }
    376390               
     
    398412        callid &= ~IPC_CALLID_ANSWERED;
    399413       
    400         futex_lock(&ipc_futex);
     414        futex_down(&ipc_futex);
    401415       
    402416        link_t *item;
     
    409423                        list_remove(&call->list);
    410424                       
    411                         futex_unlock(&ipc_futex);
     425                        futex_up(&ipc_futex);
    412426                       
    413427                        if (call->callback)
     
    420434        }
    421435       
    422         futex_unlock(&ipc_futex);
     436        futex_up(&ipc_futex);
    423437}
    424438
Note: See TracChangeset for help on using the changeset viewer.