Ignore:
File:
1 edited

Legend:

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

    ra35b458 ra36f442  
    6363static void ipc_forget_call(call_t *);
    6464
    65 /** Open channel that is assigned automatically to new tasks */
    66 answerbox_t *ipc_phone_0 = NULL;
     65/** Answerbox that new tasks are automatically connected to */
     66answerbox_t *ipc_box_0 = NULL;
    6767
    6868static slab_cache_t *call_cache;
     
    147147        list_initialize(&box->answers);
    148148        list_initialize(&box->irq_notifs);
     149        atomic_set(&box->active_calls, 0);
    149150        box->task = task;
    150151}
     
    160161bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
    161162{
    162         bool active;
     163        bool connected;
    163164
    164165        mutex_lock(&phone->lock);
    165166        irq_spinlock_lock(&box->lock, true);
    166167
    167         active = box->active;
    168         if (active) {
     168        connected = box->active && (phone->state == IPC_PHONE_CONNECTING);
     169        if (connected) {
    169170                phone->state = IPC_PHONE_CONNECTED;
    170171                phone->callee = box;
     
    176177        mutex_unlock(&phone->lock);
    177178
    178         if (!active) {
     179        if (!connected) {
    179180                /* We still have phone->kobject's reference; drop it */
    180181                kobject_put(phone->kobject);
    181182        }
    182183
    183         return active;
     184        return connected;
    184185}
    185186
     
    350351        } else {
    351352                atomic_inc(&phone->active_calls);
     353                if (call->callerbox)
     354                        atomic_inc(&call->callerbox->active_calls);
     355                else
     356                        atomic_inc(&caller->answerbox.active_calls);
     357                kobject_add_ref(phone->kobject);
    352358                call->sender = caller;
    353359                call->active = true;
     
    439445/** Disconnect phone from answerbox.
    440446 *
    441  * This call leaves the phone in the HUNGUP state. The change to 'free' is done
    442  * lazily later.
     447 * This call leaves the phone in the hung-up state. The phone is destroyed when
     448 * its last active call is answered and there are no references to it.
    443449 *
    444450 * @param phone Phone structure to be hung up.
     
    563569                list_remove(&request->ab_link);
    564570                atomic_dec(&request->caller_phone->active_calls);
     571                atomic_dec(&box->active_calls);
     572                kobject_put(request->caller_phone->kobject);
    565573        } else if (!list_empty(&box->calls)) {
    566574                /* Count received call */
     
    707715
    708716        atomic_dec(&call->caller_phone->active_calls);
     717        atomic_dec(&TASK->answerbox.active_calls);
     718        kobject_put(call->caller_phone->kobject);
    709719
    710720        SYSIPC_OP(request_forget, call);
     
    746756}
    747757
    748 static bool phone_cap_wait_cb(cap_t *cap, void *arg)
    749 {
    750         phone_t *phone = cap->kobject->phone;
    751         bool *restart = (bool *) arg;
    752 
    753         mutex_lock(&phone->lock);
    754         if ((phone->state == IPC_PHONE_HUNGUP) &&
    755             (atomic_get(&phone->active_calls) == 0)) {
    756                 phone->state = IPC_PHONE_FREE;
    757                 phone->callee = NULL;
    758         }
    759 
    760         /*
    761          * We might have had some IPC_PHONE_CONNECTING phones at the beginning
    762          * of ipc_cleanup(). Depending on whether these were forgotten or
    763          * answered, they will eventually enter the IPC_PHONE_FREE or
    764          * IPC_PHONE_CONNECTED states, respectively.  In the latter case, the
    765          * other side may slam the open phones at any time, in which case we
    766          * will get an IPC_PHONE_SLAMMED phone.
    767          */
    768         if ((phone->state == IPC_PHONE_CONNECTED) ||
    769             (phone->state == IPC_PHONE_SLAMMED)) {
    770                 mutex_unlock(&phone->lock);
    771                 ipc_phone_hangup(phone);
    772                 /*
    773                  * Now there may be one extra active call, which needs to be
    774                  * forgotten.
    775                  */
    776                 ipc_forget_all_active_calls();
    777                 *restart = true;
    778                 return false;
    779         }
    780 
    781         /*
    782          * If the hangup succeeded, it has sent a HANGUP message, the IPC is now
    783          * in HUNGUP state, we wait for the reply to come
    784          */
    785         if (phone->state != IPC_PHONE_FREE) {
    786                 mutex_unlock(&phone->lock);
    787                 return false;
    788         }
    789 
    790         mutex_unlock(&phone->lock);
    791         return true;
    792 }
    793 
    794 /** Wait for all answers to asynchronous calls to arrive. */
    795 static void ipc_wait_for_all_answered_calls(void)
    796 {
    797         call_t *call;
    798         bool restart;
    799 
    800 restart:
    801         /*
    802          * Go through all phones, until they are all free.
    803          * Locking is needed as there may be connection handshakes in progress.
    804          */
    805         restart = false;
    806         if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
    807             phone_cap_wait_cb, &restart)) {
    808                 /* Got into cleanup */
    809                 return;
    810         }
    811         if (restart)
    812                 goto restart;
    813 
    814         call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    815             SYNCH_FLAGS_NONE);
    816         assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
    817 
    818         SYSIPC_OP(answer_process, call);
    819 
    820         kobject_put(call->kobject);
    821         goto restart;
    822 }
    823 
    824758static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
    825759{
     
    830764        cap_free(cap->task, cap->handle);
    831765        return true;
     766}
     767
     768/** Wait for all answers to asynchronous calls to arrive. */
     769static void ipc_wait_for_all_answered_calls(void)
     770{
     771        while (atomic_get(&TASK->answerbox.active_calls) != 0) {
     772                call_t *call = ipc_wait_for_call(&TASK->answerbox,
     773                    SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
     774                assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
     775
     776                SYSIPC_OP(answer_process, call);
     777
     778                kobject_put(call->kobject);
     779
     780                /*
     781                 * Now there may be some new phones and new hangup calls to
     782                 * immediately forget.
     783                 */
     784                caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
     785                    phone_cap_cleanup_cb, NULL);
     786                ipc_forget_all_active_calls();
     787        }
    832788}
    833789
     
    869825        irq_spinlock_unlock(&TASK->answerbox.lock, true);
    870826
    871         /* Disconnect all our phones ('ipc_phone_hangup') */
     827        /* Hangup all phones and destroy all phone capabilities */
    872828        caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
    873829            phone_cap_cleanup_cb, NULL);
    874830
    875         /* Unsubscribe from any event notifications. */
     831        /* Unsubscribe from any event notifications */
    876832        event_cleanup_answerbox(&TASK->answerbox);
    877833
     
    899855        ipc_forget_all_active_calls();
    900856        ipc_wait_for_all_answered_calls();
     857
     858        assert(atomic_get(&TASK->answerbox.active_calls) == 0);
    901859}
    902860
     
    968926                        break;
    969927                case IPC_PHONE_HUNGUP:
    970                         printf("hung up by %p", phone->callee);
     928                        printf("hung up to %p", phone->callee);
    971929                        break;
    972930                default:
     
    1004962        irq_spinlock_lock(&task->lock, true);
    1005963        irq_spinlock_lock(&task->answerbox.lock, false);
     964
     965        printf("Active calls: %" PRIun "\n",
     966            atomic_get(&task->answerbox.active_calls));
    1006967
    1007968#ifdef __32_BITS__
Note: See TracChangeset for help on using the changeset viewer.