Ignore:
File:
1 edited

Legend:

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

    r48bcf49 r97b8ca9  
    3838 */
    3939
    40 #include <assert.h>
    4140#include <synch/spinlock.h>
    4241#include <synch/mutex.h>
    4342#include <synch/waitq.h>
    4443#include <ipc/ipc.h>
    45 #include <ipc/ipcrsc.h>
    4644#include <abi/ipc/methods.h>
    4745#include <ipc/kbox.h>
     
    5351#include <arch.h>
    5452#include <proc/task.h>
    55 #include <mem.h>
     53#include <memstr.h>
     54#include <debug.h>
    5655#include <print.h>
    5756#include <console/console.h>
     
    5958#include <arch/interrupt.h>
    6059#include <ipc/irq.h>
    61 #include <cap/cap.h>
    6260
    6361static void ipc_forget_call(call_t *);
     
    6664answerbox_t *ipc_phone_0 = NULL;
    6765
    68 static slab_cache_t *call_slab;
    69 static slab_cache_t *answerbox_slab;
    70 
    71 slab_cache_t *phone_slab = NULL;
     66static slab_cache_t *ipc_call_slab;
     67static slab_cache_t *ipc_answerbox_slab;
    7268
    7369/** Initialize a call structure.
     
    9793                if (call->buffer)
    9894                        free(call->buffer);
    99                 slab_free(call_slab, call);
     95                slab_free(ipc_call_slab, call);
    10096        }
    10197}
     
    114110call_t *ipc_call_alloc(unsigned int flags)
    115111{
    116         call_t *call = slab_alloc(call_slab, flags);
     112        call_t *call = slab_alloc(ipc_call_slab, flags);
    117113        if (call) {
    118114                _ipc_call_init(call);
     
    149145        list_initialize(&box->answers);
    150146        list_initialize(&box->irq_notifs);
     147        list_initialize(&box->irq_list);
    151148        box->task = task;
    152149}
     
    154151/** Connect a phone to an answerbox.
    155152 *
    156  * This function must be passed a reference to phone->kobject.
    157  *
    158  * @param phone  Initialized phone structure.
    159  * @param box    Initialized answerbox structure.
    160  * @return       True if the phone was connected, false otherwise.
     153 * @param phone Initialized phone structure.
     154 * @param box   Initialized answerbox structure.
     155 * @return      True if the phone was connected, false otherwise.
    161156 */
    162157bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
     
    171166                phone->state = IPC_PHONE_CONNECTED;
    172167                phone->callee = box;
    173                 /* Pass phone->kobject reference to box->connected_phones */
    174168                list_append(&phone->link, &box->connected_phones);
    175169        }
     
    177171        irq_spinlock_unlock(&box->lock, true);
    178172        mutex_unlock(&phone->lock);
    179 
    180         if (!active) {
    181                 /* We still have phone->kobject's reference; drop it */
    182                 kobject_put(phone->kobject);
    183         }
    184173
    185174        return active;
     
    199188        phone->state = IPC_PHONE_FREE;
    200189        atomic_set(&phone->active_calls, 0);
    201         phone->kobject = NULL;
    202190}
    203191
     
    212200int ipc_call_sync(phone_t *phone, call_t *request)
    213201{
    214         answerbox_t *mybox = slab_alloc(answerbox_slab, 0);
     202        answerbox_t *mybox = slab_alloc(ipc_answerbox_slab, 0);
    215203        ipc_answerbox_init(mybox, TASK);
    216204       
     
    220208        int rc = ipc_call(phone, request);
    221209        if (rc != EOK) {
    222                 slab_free(answerbox_slab, mybox);
     210                slab_free(ipc_answerbox_slab, mybox);
    223211                return rc;
    224212        }
     
    239227                spinlock_lock(&TASK->active_calls_lock);
    240228
    241                 assert(!request->forget);
     229                ASSERT(!request->forget);
    242230
    243231                bool answered = !request->active;
     
    265253                }
    266254        }
    267         assert(!answer || request == answer);
    268        
    269         slab_free(answerbox_slab, mybox);
     255        ASSERT(!answer || request == answer);
     256       
     257        slab_free(ipc_answerbox_slab, mybox);
    270258        return rc;
    271259}
     
    465453                list_remove(&phone->link);
    466454                irq_spinlock_unlock(&box->lock, true);
    467 
    468                 /* Drop the answerbox reference */
    469                 kobject_put(phone->kobject);
    470455               
    471456                call_t *call = ipc_call_alloc(0);
     
    646631               
    647632                /* Disconnect phone */
    648                 assert(phone->state == IPC_PHONE_CONNECTED);
     633                ASSERT(phone->state == IPC_PHONE_CONNECTED);
    649634               
    650635                list_remove(&phone->link);
     
    670655
    671656                        task_release(phone->caller);
    672 
    673                         kobject_put(phone->kobject);
    674657                       
    675658                        /* Must start again */
     
    678661               
    679662                mutex_unlock(&phone->lock);
    680                 kobject_put(phone->kobject);
    681663        }
    682664       
     
    686668static void ipc_forget_call(call_t *call)
    687669{
    688         assert(spinlock_locked(&TASK->active_calls_lock));
    689         assert(spinlock_locked(&call->forget_lock));
     670        ASSERT(spinlock_locked(&TASK->active_calls_lock));
     671        ASSERT(spinlock_locked(&call->forget_lock));
    690672
    691673        /*
     
    725707                 * Nota bene: there may still be answers waiting for pick up.
    726708                 */
    727                 spinlock_unlock(&TASK->active_calls_lock);
     709                spinlock_unlock(&TASK->active_calls_lock);     
    728710                return;
    729711        }
     
    738720                 * call on the list.
    739721                 */
    740                 spinlock_unlock(&TASK->active_calls_lock);
     722                spinlock_unlock(&TASK->active_calls_lock);     
    741723                goto restart;
    742724        }
     
    745727
    746728        goto restart;
    747 }
    748 
    749 static bool phone_cap_wait_cb(cap_t *cap, void *arg)
    750 {
    751         phone_t *phone = cap->kobject->phone;
    752         bool *restart = (bool *) arg;
    753 
    754         mutex_lock(&phone->lock);
    755         if ((phone->state == IPC_PHONE_HUNGUP) &&
    756             (atomic_get(&phone->active_calls) == 0)) {
    757                 phone->state = IPC_PHONE_FREE;
    758                 phone->callee = NULL;
    759         }
    760 
    761         /*
    762          * We might have had some IPC_PHONE_CONNECTING phones at the beginning
    763          * of ipc_cleanup(). Depending on whether these were forgotten or
    764          * answered, they will eventually enter the IPC_PHONE_FREE or
    765          * IPC_PHONE_CONNECTED states, respectively.  In the latter case, the
    766          * other side may slam the open phones at any time, in which case we
    767          * will get an IPC_PHONE_SLAMMED phone.
    768          */
    769         if ((phone->state == IPC_PHONE_CONNECTED) ||
    770             (phone->state == IPC_PHONE_SLAMMED)) {
    771                 mutex_unlock(&phone->lock);
    772                 ipc_phone_hangup(phone);
    773                 /*
    774                  * Now there may be one extra active call, which needs to be
    775                  * forgotten.
    776                  */
    777                 ipc_forget_all_active_calls();
    778                 *restart = true;
    779                 return false;
    780         }
    781 
    782         /*
    783          * If the hangup succeeded, it has sent a HANGUP message, the IPC is now
    784          * in HUNGUP state, we wait for the reply to come
    785          */
    786         if (phone->state != IPC_PHONE_FREE) {
    787                 mutex_unlock(&phone->lock);
    788                 return false;
    789         }
    790 
    791         mutex_unlock(&phone->lock);
    792         return true;
    793729}
    794730
     
    797733{
    798734        call_t *call;
    799         bool restart;
     735        size_t i;
    800736
    801737restart:
     
    804740         * Locking is needed as there may be connection handshakes in progress.
    805741         */
    806         restart = false;
    807         if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
    808             phone_cap_wait_cb, &restart)) {
    809                 /* Got into cleanup */
     742        for (i = 0; i < IPC_MAX_PHONES; i++) {
     743                phone_t *phone = &TASK->phones[i];
     744
     745                mutex_lock(&phone->lock);       
     746                if ((phone->state == IPC_PHONE_HUNGUP) &&
     747                    (atomic_get(&phone->active_calls) == 0)) {
     748                        phone->state = IPC_PHONE_FREE;
     749                        phone->callee = NULL;
     750                }
     751
     752                /*
     753                 * We might have had some IPC_PHONE_CONNECTING phones at the
     754                 * beginning of ipc_cleanup(). Depending on whether these were
     755                 * forgotten or answered, they will eventually enter the
     756                 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
     757                 * In the latter case, the other side may slam the open phones
     758                 * at any time, in which case we will get an IPC_PHONE_SLAMMED
     759                 * phone.
     760                 */
     761                if ((phone->state == IPC_PHONE_CONNECTED) ||
     762                    (phone->state == IPC_PHONE_SLAMMED)) {
     763                        mutex_unlock(&phone->lock);
     764                        ipc_phone_hangup(phone);
     765                        /*
     766                         * Now there may be one extra active call, which needs
     767                         * to be forgotten.
     768                         */
     769                        ipc_forget_all_active_calls();
     770                        goto restart;
     771                }
     772
     773                /*
     774                 * If the hangup succeeded, it has sent a HANGUP message, the
     775                 * IPC is now in HUNGUP state, we wait for the reply to come
     776                 */
     777                if (phone->state != IPC_PHONE_FREE) {
     778                        mutex_unlock(&phone->lock);
     779                        break;
     780                }
     781
     782                mutex_unlock(&phone->lock);
     783        }
     784               
     785        /* Got into cleanup */
     786        if (i == IPC_MAX_PHONES)
    810787                return;
    811         }
    812         if (restart)
    813                 goto restart;
    814        
     788               
    815789        call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    816790            SYNCH_FLAGS_NONE);
    817         assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
     791        ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
    818792
    819793        SYSIPC_OP(answer_process, call);
     
    821795        ipc_call_free(call);
    822796        goto restart;
    823 }
    824 
    825 static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
    826 {
    827         ipc_phone_hangup(cap->kobject->phone);
    828         return true;
    829 }
    830 
    831 static bool irq_cap_cleanup_cb(cap_t *cap, void *arg)
    832 {
    833         ipc_irq_unsubscribe(&TASK->answerbox, cap->handle);
    834         return true;
    835797}
    836798
     
    854816
    855817        /* Disconnect all our phones ('ipc_phone_hangup') */
    856         caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
    857             phone_cap_cleanup_cb, NULL);
     818        for (size_t i = 0; i < IPC_MAX_PHONES; i++)
     819                ipc_phone_hangup(&TASK->phones[i]);
    858820       
    859821        /* Unsubscribe from any event notifications. */
    860822        event_cleanup_answerbox(&TASK->answerbox);
    861823       
    862         /* Disconnect all connected IRQs */
    863         caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_IRQ, irq_cap_cleanup_cb,
    864             NULL);
     824        /* Disconnect all connected irqs */
     825        ipc_irq_cleanup(&TASK->answerbox);
    865826       
    866827        /* Disconnect all phones connected to our regular answerbox */
     
    886847void ipc_init(void)
    887848{
    888         call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,
     849        ipc_call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,
    889850            NULL, 0);
    890         phone_slab = slab_cache_create("phone_t", sizeof(phone_t), 0, NULL,
    891             NULL, 0);
    892         answerbox_slab = slab_cache_create("answerbox_t", sizeof(answerbox_t),
    893             0, NULL, NULL, 0);
     851        ipc_answerbox_slab = slab_cache_create("answerbox_t",
     852            sizeof(answerbox_t), 0, NULL, NULL, 0);
    894853}
    895854
     
    926885}
    927886
    928 static bool print_task_phone_cb(cap_t *cap, void *arg)
    929 {
    930         phone_t *phone = cap->kobject->phone;
    931 
    932         mutex_lock(&phone->lock);
    933         if (phone->state != IPC_PHONE_FREE) {
    934                 printf("%-11d %7" PRIun " ", cap->handle,
    935                     atomic_get(&phone->active_calls));
    936                
    937                 switch (phone->state) {
    938                 case IPC_PHONE_CONNECTING:
    939                         printf("connecting");
    940                         break;
    941                 case IPC_PHONE_CONNECTED:
    942                         printf("connected to %" PRIu64 " (%s)",
    943                             phone->callee->task->taskid,
    944                             phone->callee->task->name);
    945                         break;
    946                 case IPC_PHONE_SLAMMED:
    947                         printf("slammed by %p", phone->callee);
    948                         break;
    949                 case IPC_PHONE_HUNGUP:
    950                         printf("hung up by %p", phone->callee);
    951                         break;
    952                 default:
    953                         break;
    954                 }
    955                
    956                 printf("\n");
    957         }
    958         mutex_unlock(&phone->lock);
    959 
    960         return true;
    961 }
    962 
    963887/** List answerbox contents.
    964888 *
     
    970894        irq_spinlock_lock(&tasks_lock, true);
    971895        task_t *task = task_find_by_id(taskid);
     896       
    972897        if (!task) {
    973898                irq_spinlock_unlock(&tasks_lock, true);
    974899                return;
    975900        }
    976         task_hold(task);
    977         irq_spinlock_unlock(&tasks_lock, true);
    978        
    979         printf("[phone cap] [calls] [state\n");
    980        
    981         caps_apply_to_kobject_type(task, KOBJECT_TYPE_PHONE,
    982             print_task_phone_cb, NULL);
    983        
    984         irq_spinlock_lock(&task->lock, true);
     901       
     902        /* Hand-over-hand locking */
     903        irq_spinlock_exchange(&tasks_lock, &task->lock);
     904       
     905        printf("[phone id] [calls] [state\n");
     906       
     907        size_t i;
     908        for (i = 0; i < IPC_MAX_PHONES; i++) {
     909                if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
     910                        printf("%-10zu (mutex busy)\n", i);
     911                        continue;
     912                }
     913               
     914                if (task->phones[i].state != IPC_PHONE_FREE) {
     915                        printf("%-10zu %7" PRIun " ", i,
     916                            atomic_get(&task->phones[i].active_calls));
     917                       
     918                        switch (task->phones[i].state) {
     919                        case IPC_PHONE_CONNECTING:
     920                                printf("connecting");
     921                                break;
     922                        case IPC_PHONE_CONNECTED:
     923                                printf("connected to %" PRIu64 " (%s)",
     924                                    task->phones[i].callee->task->taskid,
     925                                    task->phones[i].callee->task->name);
     926                                break;
     927                        case IPC_PHONE_SLAMMED:
     928                                printf("slammed by %p",
     929                                    task->phones[i].callee);
     930                                break;
     931                        case IPC_PHONE_HUNGUP:
     932                                printf("hung up by %p",
     933                                    task->phones[i].callee);
     934                                break;
     935                        default:
     936                                break;
     937                        }
     938                       
     939                        printf("\n");
     940                }
     941               
     942                mutex_unlock(&task->phones[i].lock);
     943        }
     944       
    985945        irq_spinlock_lock(&task->answerbox.lock, false);
    986946       
     
    1004964        irq_spinlock_unlock(&task->answerbox.lock, false);
    1005965        irq_spinlock_unlock(&task->lock, true);
    1006 
    1007         task_release(task);
    1008966}
    1009967
Note: See TracChangeset for help on using the changeset viewer.