Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ipc/ipc.c

    r97b8ca9 r466e95f7  
    5959#include <ipc/irq.h>
    6060
    61 static void ipc_forget_call(call_t *);
    62 
    6361/** Open channel that is assigned automatically to new tasks */
    6462answerbox_t *ipc_phone_0 = NULL;
     
    7977        call->forget = false;
    8078        call->sender = NULL;
    81         call->callerbox = NULL;
    8279        call->buffer = NULL;
    8380}
     
    188185        phone->state = IPC_PHONE_FREE;
    189186        atomic_set(&phone->active_calls, 0);
    190 }
    191 
    192 /** Helper function to facilitate synchronous calls.
    193  *
    194  * @param phone   Destination kernel phone structure.
    195  * @param request Call structure with request.
    196  *
    197  * @return EOK on success or a negative error code.
    198  *
    199  */
    200 int ipc_call_sync(phone_t *phone, call_t *request)
    201 {
    202         answerbox_t *mybox = slab_alloc(ipc_answerbox_slab, 0);
    203         ipc_answerbox_init(mybox, TASK);
    204        
    205         /* We will receive data in a special box. */
    206         request->callerbox = mybox;
    207        
    208         int rc = ipc_call(phone, request);
    209         if (rc != EOK) {
    210                 slab_free(ipc_answerbox_slab, mybox);
    211                 return rc;
    212         }
    213 
    214         call_t *answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
    215             SYNCH_FLAGS_INTERRUPTIBLE);
    216         if (!answer) {
    217 
    218                 /*
    219                  * The sleep was interrupted.
    220                  *
    221                  * There are two possibilities now:
    222                  * 1) the call gets answered before we manage to forget it
    223                  * 2) we manage to forget the call before it gets answered
    224                  */
    225 
    226                 spinlock_lock(&request->forget_lock);
    227                 spinlock_lock(&TASK->active_calls_lock);
    228 
    229                 ASSERT(!request->forget);
    230 
    231                 bool answered = !request->active;
    232                 if (!answered) {
    233                         /*
    234                          * The call is not yet answered and we won the race to
    235                          * forget it.
    236                          */
    237                         ipc_forget_call(request);       /* releases locks */
    238                         rc = EINTR;
    239                        
    240                 } else {
    241                         spinlock_unlock(&TASK->active_calls_lock);
    242                         spinlock_unlock(&request->forget_lock);
    243                 }
    244 
    245                 if (answered) {
    246                         /*
    247                          * The other side won the race to answer the call.
    248                          * It is safe to wait for the answer uninterruptibly
    249                          * now.
    250                          */
    251                         answer = ipc_wait_for_call(mybox, SYNCH_NO_TIMEOUT,
    252                             SYNCH_FLAGS_NONE);
    253                 }
    254         }
    255         ASSERT(!answer || request == answer);
    256        
    257         slab_free(ipc_answerbox_slab, mybox);
    258         return rc;
    259187}
    260188
     
    292220        spinlock_unlock(&call->forget_lock);
    293221
    294         answerbox_t *callerbox = call->callerbox ? call->callerbox :
    295             &call->sender->answerbox;
     222        answerbox_t *callerbox = &call->sender->answerbox;
    296223        bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    297224       
     
    328255}
    329256
    330 static void _ipc_call_actions_internal(phone_t *phone, call_t *call,
    331     bool preforget)
     257static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
    332258{
    333259        task_t *caller = phone->caller;
    334260
     261        atomic_inc(&phone->active_calls);
    335262        call->caller_phone = phone;
    336 
    337         if (preforget) {
    338                 call->forget = true;
    339         } else {
    340                 atomic_inc(&phone->active_calls);
    341                 call->sender = caller;
    342                 call->active = true;
    343                 spinlock_lock(&caller->active_calls_lock);
    344                 list_append(&call->ta_link, &caller->active_calls);
    345                 spinlock_unlock(&caller->active_calls_lock);
    346         }
     263        call->sender = caller;
     264
     265        call->active = true;
     266        spinlock_lock(&caller->active_calls_lock);
     267        list_append(&call->ta_link, &caller->active_calls);
     268        spinlock_unlock(&caller->active_calls_lock);
    347269
    348270        call->data.phone = phone;
     
    362284void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    363285{
    364         _ipc_call_actions_internal(phone, call, false);
     286        _ipc_call_actions_internal(phone, call);
    365287        IPC_SET_RETVAL(call->data, err);
    366288        _ipc_answer_free_call(call, false);
     
    369291/** Unsafe unchecking version of ipc_call.
    370292 *
    371  * @param phone     Phone structure the call comes from.
    372  * @param box       Destination answerbox structure.
    373  * @param call      Call structure with request.
    374  * @param preforget If true, the call will be delivered already forgotten.
    375  *
    376  */
    377 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call,
    378     bool preforget)
     293 * @param phone Phone structure the call comes from.
     294 * @param box   Destination answerbox structure.
     295 * @param call  Call structure with request.
     296 *
     297 */
     298static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    379299{
    380300        task_t *caller = phone->caller;
     
    386306       
    387307        if (!(call->flags & IPC_CALL_FORWARDED))
    388                 _ipc_call_actions_internal(phone, call, preforget);
     308                _ipc_call_actions_internal(phone, call);
    389309       
    390310        irq_spinlock_lock(&box->lock, true);
     
    420340       
    421341        answerbox_t *box = phone->callee;
    422         _ipc_call(phone, box, call, false);
     342        _ipc_call(phone, box, call);
    423343       
    424344        mutex_unlock(&phone->lock);
     
    458378                call->request_method = IPC_M_PHONE_HUNGUP;
    459379                call->flags |= IPC_CALL_DISCARD_ANSWER;
    460                 _ipc_call(phone, box, call, false);
     380                _ipc_call(phone, box, call);
    461381        }
    462382       
     
    617537        phone_t *phone;
    618538        DEADLOCK_PROBE_INIT(p_phonelck);
     539       
     540        call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
    619541       
    620542        /* Disconnect all phones connected to our answerbox */
     
    637559               
    638560                if (notify_box) {
    639                         task_hold(phone->caller);
    640561                        mutex_unlock(&phone->lock);
    641562                        irq_spinlock_unlock(&box->lock, true);
    642563
     564                        // FIXME: phone can become deallocated at any time now
     565
    643566                        /*
    644                          * Send one call to the answerbox for each phone.
    645                          * Used to make sure the kbox thread wakes up after
    646                          * the last phone has been disconnected. The call is
    647                          * forgotten upon sending, so the "caller" may cease
    648                          * to exist as soon as we release it.
     567                         * Send one message to the answerbox for each
     568                         * phone. Used to make sure the kbox thread
     569                         * wakes up after the last phone has been
     570                         * disconnected.
    649571                         */
    650                         call_t *call = ipc_call_alloc(0);
    651572                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
    652573                        call->request_method = IPC_M_PHONE_HUNGUP;
    653574                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    654                         _ipc_call(phone, box, call, true);
    655 
    656                         task_release(phone->caller);
     575                        _ipc_call(phone, box, call);
     576                       
     577                        /* Allocate another call in advance */
     578                        call = ipc_call_alloc(0);
    657579                       
    658580                        /* Must start again */
     
    664586       
    665587        irq_spinlock_unlock(&box->lock, true);
    666 }
    667 
    668 static void ipc_forget_call(call_t *call)
    669 {
    670         ASSERT(spinlock_locked(&TASK->active_calls_lock));
    671         ASSERT(spinlock_locked(&call->forget_lock));
    672 
    673         /*
    674          * Forget the call and donate it to the task which holds up the answer.
    675          */
    676 
    677         call->forget = true;
    678         call->sender = NULL;
    679         list_remove(&call->ta_link);
    680 
    681         /*
    682          * The call may be freed by _ipc_answer_free_call() before we are done
    683          * with it; to avoid working with a destroyed call_t structure, we
    684          * must hold a reference to it.
    685          */
    686         ipc_call_hold(call);
    687 
    688         spinlock_unlock(&call->forget_lock);
    689         spinlock_unlock(&TASK->active_calls_lock);
    690 
    691         atomic_dec(&call->caller_phone->active_calls);
    692 
    693         SYSIPC_OP(request_forget, call);
    694 
    695         ipc_call_release(call);
     588       
     589        /* Free unused call */
     590        if (call)
     591                ipc_call_free(call);
    696592}
    697593
     
    724620        }
    725621
    726         ipc_forget_call(call);
     622        /*
     623         * Forget the call and donate it to the task which holds up the answer.
     624         */
     625
     626        call->forget = true;
     627        call->sender = NULL;
     628        list_remove(&call->ta_link);
     629
     630        /*
     631         * The call may be freed by _ipc_answer_free_call() before we are done
     632         * with it; to avoid working with a destroyed call_t structure, we
     633         * must hold a reference to it.
     634         */
     635        ipc_call_hold(call);
     636
     637        spinlock_unlock(&call->forget_lock);
     638        spinlock_unlock(&TASK->active_calls_lock);
     639
     640        atomic_dec(&call->caller_phone->active_calls);
     641
     642        SYSIPC_OP(request_forget, call);
     643
     644        ipc_call_release(call);
    727645
    728646        goto restart;
     
    837755        ipc_cleanup_call_list(&TASK->answerbox,
    838756            &TASK->answerbox.dispatched_calls);
    839        
     757
    840758        ipc_forget_all_active_calls();
    841759        ipc_wait_for_all_answered_calls();
     
    856774static void ipc_print_call_list(list_t *list)
    857775{
    858         list_foreach(*list, ab_link, call_t, call) {
     776        list_foreach(*list, cur) {
     777                call_t *call = list_get_instance(cur, call_t, ab_link);
     778               
    859779#ifdef __32_BITS__
    860780                printf("%10p ", call);
Note: See TracChangeset for help on using the changeset viewer.