Ignore:
File:
1 edited

Legend:

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

    ra36f442 ra35b458  
    6363static void ipc_forget_call(call_t *);
    6464
    65 /** Answerbox that new tasks are automatically connected to */
    66 answerbox_t *ipc_box_0 = NULL;
     65/** Open channel that is assigned automatically to new tasks */
     66answerbox_t *ipc_phone_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);
    150149        box->task = task;
    151150}
     
    161160bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
    162161{
    163         bool connected;
     162        bool active;
    164163
    165164        mutex_lock(&phone->lock);
    166165        irq_spinlock_lock(&box->lock, true);
    167166
    168         connected = box->active && (phone->state == IPC_PHONE_CONNECTING);
    169         if (connected) {
     167        active = box->active;
     168        if (active) {
    170169                phone->state = IPC_PHONE_CONNECTED;
    171170                phone->callee = box;
     
    177176        mutex_unlock(&phone->lock);
    178177
    179         if (!connected) {
     178        if (!active) {
    180179                /* We still have phone->kobject's reference; drop it */
    181180                kobject_put(phone->kobject);
    182181        }
    183182
    184         return connected;
     183        return active;
    185184}
    186185
     
    351350        } else {
    352351                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);
    358352                call->sender = caller;
    359353                call->active = true;
     
    445439/** Disconnect phone from answerbox.
    446440 *
    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.
     441 * This call leaves the phone in the HUNGUP state. The change to 'free' is done
     442 * lazily later.
    449443 *
    450444 * @param phone Phone structure to be hung up.
     
    569563                list_remove(&request->ab_link);
    570564                atomic_dec(&request->caller_phone->active_calls);
    571                 atomic_dec(&box->active_calls);
    572                 kobject_put(request->caller_phone->kobject);
    573565        } else if (!list_empty(&box->calls)) {
    574566                /* Count received call */
     
    715707
    716708        atomic_dec(&call->caller_phone->active_calls);
    717         atomic_dec(&TASK->answerbox.active_calls);
    718         kobject_put(call->caller_phone->kobject);
    719709
    720710        SYSIPC_OP(request_forget, call);
     
    756746}
    757747
     748static 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. */
     795static void ipc_wait_for_all_answered_calls(void)
     796{
     797        call_t *call;
     798        bool restart;
     799
     800restart:
     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
    758824static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
    759825{
     
    764830        cap_free(cap->task, cap->handle);
    765831        return true;
    766 }
    767 
    768 /** Wait for all answers to asynchronous calls to arrive. */
    769 static 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         }
    788832}
    789833
     
    825869        irq_spinlock_unlock(&TASK->answerbox.lock, true);
    826870
    827         /* Hangup all phones and destroy all phone capabilities */
     871        /* Disconnect all our phones ('ipc_phone_hangup') */
    828872        caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
    829873            phone_cap_cleanup_cb, NULL);
    830874
    831         /* Unsubscribe from any event notifications */
     875        /* Unsubscribe from any event notifications. */
    832876        event_cleanup_answerbox(&TASK->answerbox);
    833877
     
    855899        ipc_forget_all_active_calls();
    856900        ipc_wait_for_all_answered_calls();
    857 
    858         assert(atomic_get(&TASK->answerbox.active_calls) == 0);
    859901}
    860902
     
    926968                        break;
    927969                case IPC_PHONE_HUNGUP:
    928                         printf("hung up to %p", phone->callee);
     970                        printf("hung up by %p", phone->callee);
    929971                        break;
    930972                default:
     
    9621004        irq_spinlock_lock(&task->lock, true);
    9631005        irq_spinlock_lock(&task->answerbox.lock, false);
    964 
    965         printf("Active calls: %" PRIun "\n",
    966             atomic_get(&task->answerbox.active_calls));
    9671006
    9681007#ifdef __32_BITS__
Note: See TracChangeset for help on using the changeset viewer.