Changeset 97b8ca9 in mainline


Ignore:
Timestamp:
2016-09-11T08:44:04Z (8 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
560b81c
Parents:
0b00599
Message:

Fix race between ipc_answerbox_slam_phones() and ipc_cleanup()

We modify _ipc_call() to support sending of pre-forgotten calls. This is
handy in ipc_answerbox_slam_phones() when after slamming a client's
phone, we may no longer be sure of the client's continued existence.

A pre-forgotten call is delivered to the callee in an already forgotten
state, so that the caller is no longer expected to wait for it nor it is
expected to be still around. The caller is held alive for the necessary
time, but can disappear as soon as we release it.

File:
1 edited

Legend:

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

    r0b00599 r97b8ca9  
    328328}
    329329
    330 static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
     330static void _ipc_call_actions_internal(phone_t *phone, call_t *call,
     331    bool preforget)
    331332{
    332333        task_t *caller = phone->caller;
    333334
    334         atomic_inc(&phone->active_calls);
    335335        call->caller_phone = phone;
    336         call->sender = caller;
    337 
    338         call->active = true;
    339         spinlock_lock(&caller->active_calls_lock);
    340         list_append(&call->ta_link, &caller->active_calls);
    341         spinlock_unlock(&caller->active_calls_lock);
     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        }
    342347
    343348        call->data.phone = phone;
     
    357362void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    358363{
    359         _ipc_call_actions_internal(phone, call);
     364        _ipc_call_actions_internal(phone, call, false);
    360365        IPC_SET_RETVAL(call->data, err);
    361366        _ipc_answer_free_call(call, false);
     
    364369/** Unsafe unchecking version of ipc_call.
    365370 *
    366  * @param phone Phone structure the call comes from.
    367  * @param box   Destination answerbox structure.
    368  * @param call  Call structure with request.
    369  *
    370  */
    371 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
     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 */
     377static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call,
     378    bool preforget)
    372379{
    373380        task_t *caller = phone->caller;
     
    379386       
    380387        if (!(call->flags & IPC_CALL_FORWARDED))
    381                 _ipc_call_actions_internal(phone, call);
     388                _ipc_call_actions_internal(phone, call, preforget);
    382389       
    383390        irq_spinlock_lock(&box->lock, true);
     
    413420       
    414421        answerbox_t *box = phone->callee;
    415         _ipc_call(phone, box, call);
     422        _ipc_call(phone, box, call, false);
    416423       
    417424        mutex_unlock(&phone->lock);
     
    451458                call->request_method = IPC_M_PHONE_HUNGUP;
    452459                call->flags |= IPC_CALL_DISCARD_ANSWER;
    453                 _ipc_call(phone, box, call);
     460                _ipc_call(phone, box, call, false);
    454461        }
    455462       
     
    610617        phone_t *phone;
    611618        DEADLOCK_PROBE_INIT(p_phonelck);
    612        
    613         call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
    614619       
    615620        /* Disconnect all phones connected to our answerbox */
     
    632637               
    633638                if (notify_box) {
     639                        task_hold(phone->caller);
    634640                        mutex_unlock(&phone->lock);
    635641                        irq_spinlock_unlock(&box->lock, true);
    636642
    637                         // FIXME: phone can become deallocated at any time now
    638 
    639643                        /*
    640                          * Send one message to the answerbox for each
    641                          * phone. Used to make sure the kbox thread
    642                          * wakes up after the last phone has been
    643                          * disconnected.
     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.
    644649                         */
     650                        call_t *call = ipc_call_alloc(0);
    645651                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
    646652                        call->request_method = IPC_M_PHONE_HUNGUP;
    647653                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    648                         _ipc_call(phone, box, call);
    649                        
    650                         /* Allocate another call in advance */
    651                         call = ipc_call_alloc(0);
     654                        _ipc_call(phone, box, call, true);
     655
     656                        task_release(phone->caller);
    652657                       
    653658                        /* Must start again */
     
    659664       
    660665        irq_spinlock_unlock(&box->lock, true);
    661        
    662         /* Free unused call */
    663         if (call)
    664                 ipc_call_free(call);
    665666}
    666667
Note: See TracChangeset for help on using the changeset viewer.