Ignore:
File:
1 edited

Legend:

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

    r97b8ca9 r48bcf49  
    3838 */
    3939
     40#include <assert.h>
    4041#include <synch/spinlock.h>
    4142#include <synch/mutex.h>
    4243#include <synch/waitq.h>
    4344#include <ipc/ipc.h>
     45#include <ipc/ipcrsc.h>
    4446#include <abi/ipc/methods.h>
    4547#include <ipc/kbox.h>
     
    5153#include <arch.h>
    5254#include <proc/task.h>
    53 #include <memstr.h>
    54 #include <debug.h>
     55#include <mem.h>
    5556#include <print.h>
    5657#include <console/console.h>
     
    5859#include <arch/interrupt.h>
    5960#include <ipc/irq.h>
     61#include <cap/cap.h>
    6062
    6163static void ipc_forget_call(call_t *);
     
    6466answerbox_t *ipc_phone_0 = NULL;
    6567
    66 static slab_cache_t *ipc_call_slab;
    67 static slab_cache_t *ipc_answerbox_slab;
     68static slab_cache_t *call_slab;
     69static slab_cache_t *answerbox_slab;
     70
     71slab_cache_t *phone_slab = NULL;
    6872
    6973/** Initialize a call structure.
     
    9397                if (call->buffer)
    9498                        free(call->buffer);
    95                 slab_free(ipc_call_slab, call);
     99                slab_free(call_slab, call);
    96100        }
    97101}
     
    110114call_t *ipc_call_alloc(unsigned int flags)
    111115{
    112         call_t *call = slab_alloc(ipc_call_slab, flags);
     116        call_t *call = slab_alloc(call_slab, flags);
    113117        if (call) {
    114118                _ipc_call_init(call);
     
    145149        list_initialize(&box->answers);
    146150        list_initialize(&box->irq_notifs);
    147         list_initialize(&box->irq_list);
    148151        box->task = task;
    149152}
     
    151154/** Connect a phone to an answerbox.
    152155 *
    153  * @param phone Initialized phone structure.
    154  * @param box   Initialized answerbox structure.
    155  * @return      True if the phone was connected, false otherwise.
     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.
    156161 */
    157162bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
     
    166171                phone->state = IPC_PHONE_CONNECTED;
    167172                phone->callee = box;
     173                /* Pass phone->kobject reference to box->connected_phones */
    168174                list_append(&phone->link, &box->connected_phones);
    169175        }
     
    171177        irq_spinlock_unlock(&box->lock, true);
    172178        mutex_unlock(&phone->lock);
     179
     180        if (!active) {
     181                /* We still have phone->kobject's reference; drop it */
     182                kobject_put(phone->kobject);
     183        }
    173184
    174185        return active;
     
    188199        phone->state = IPC_PHONE_FREE;
    189200        atomic_set(&phone->active_calls, 0);
     201        phone->kobject = NULL;
    190202}
    191203
     
    200212int ipc_call_sync(phone_t *phone, call_t *request)
    201213{
    202         answerbox_t *mybox = slab_alloc(ipc_answerbox_slab, 0);
     214        answerbox_t *mybox = slab_alloc(answerbox_slab, 0);
    203215        ipc_answerbox_init(mybox, TASK);
    204216       
     
    208220        int rc = ipc_call(phone, request);
    209221        if (rc != EOK) {
    210                 slab_free(ipc_answerbox_slab, mybox);
     222                slab_free(answerbox_slab, mybox);
    211223                return rc;
    212224        }
     
    227239                spinlock_lock(&TASK->active_calls_lock);
    228240
    229                 ASSERT(!request->forget);
     241                assert(!request->forget);
    230242
    231243                bool answered = !request->active;
     
    253265                }
    254266        }
    255         ASSERT(!answer || request == answer);
    256        
    257         slab_free(ipc_answerbox_slab, mybox);
     267        assert(!answer || request == answer);
     268       
     269        slab_free(answerbox_slab, mybox);
    258270        return rc;
    259271}
     
    453465                list_remove(&phone->link);
    454466                irq_spinlock_unlock(&box->lock, true);
     467
     468                /* Drop the answerbox reference */
     469                kobject_put(phone->kobject);
    455470               
    456471                call_t *call = ipc_call_alloc(0);
     
    631646               
    632647                /* Disconnect phone */
    633                 ASSERT(phone->state == IPC_PHONE_CONNECTED);
     648                assert(phone->state == IPC_PHONE_CONNECTED);
    634649               
    635650                list_remove(&phone->link);
     
    655670
    656671                        task_release(phone->caller);
     672
     673                        kobject_put(phone->kobject);
    657674                       
    658675                        /* Must start again */
     
    661678               
    662679                mutex_unlock(&phone->lock);
     680                kobject_put(phone->kobject);
    663681        }
    664682       
     
    668686static void ipc_forget_call(call_t *call)
    669687{
    670         ASSERT(spinlock_locked(&TASK->active_calls_lock));
    671         ASSERT(spinlock_locked(&call->forget_lock));
     688        assert(spinlock_locked(&TASK->active_calls_lock));
     689        assert(spinlock_locked(&call->forget_lock));
    672690
    673691        /*
     
    707725                 * Nota bene: there may still be answers waiting for pick up.
    708726                 */
    709                 spinlock_unlock(&TASK->active_calls_lock);     
     727                spinlock_unlock(&TASK->active_calls_lock);
    710728                return;
    711729        }
     
    720738                 * call on the list.
    721739                 */
    722                 spinlock_unlock(&TASK->active_calls_lock);     
     740                spinlock_unlock(&TASK->active_calls_lock);
    723741                goto restart;
    724742        }
     
    727745
    728746        goto restart;
     747}
     748
     749static 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;
    729793}
    730794
     
    733797{
    734798        call_t *call;
    735         size_t i;
     799        bool restart;
    736800
    737801restart:
     
    740804         * Locking is needed as there may be connection handshakes in progress.
    741805         */
    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)
     806        restart = false;
     807        if (caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
     808            phone_cap_wait_cb, &restart)) {
     809                /* Got into cleanup */
    787810                return;
    788                
     811        }
     812        if (restart)
     813                goto restart;
     814       
    789815        call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    790816            SYNCH_FLAGS_NONE);
    791         ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
     817        assert(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
    792818
    793819        SYSIPC_OP(answer_process, call);
     
    795821        ipc_call_free(call);
    796822        goto restart;
     823}
     824
     825static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
     826{
     827        ipc_phone_hangup(cap->kobject->phone);
     828        return true;
     829}
     830
     831static bool irq_cap_cleanup_cb(cap_t *cap, void *arg)
     832{
     833        ipc_irq_unsubscribe(&TASK->answerbox, cap->handle);
     834        return true;
    797835}
    798836
     
    816854
    817855        /* Disconnect all our phones ('ipc_phone_hangup') */
    818         for (size_t i = 0; i < IPC_MAX_PHONES; i++)
    819                 ipc_phone_hangup(&TASK->phones[i]);
     856        caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_PHONE,
     857            phone_cap_cleanup_cb, NULL);
    820858       
    821859        /* Unsubscribe from any event notifications. */
    822860        event_cleanup_answerbox(&TASK->answerbox);
    823861       
    824         /* Disconnect all connected irqs */
    825         ipc_irq_cleanup(&TASK->answerbox);
     862        /* Disconnect all connected IRQs */
     863        caps_apply_to_kobject_type(TASK, KOBJECT_TYPE_IRQ, irq_cap_cleanup_cb,
     864            NULL);
    826865       
    827866        /* Disconnect all phones connected to our regular answerbox */
     
    847886void ipc_init(void)
    848887{
    849         ipc_call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,
     888        call_slab = slab_cache_create("call_t", sizeof(call_t), 0, NULL,
    850889            NULL, 0);
    851         ipc_answerbox_slab = slab_cache_create("answerbox_t",
    852             sizeof(answerbox_t), 0, NULL, 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);
    853894}
    854895
     
    885926}
    886927
     928static 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
    887963/** List answerbox contents.
    888964 *
     
    894970        irq_spinlock_lock(&tasks_lock, true);
    895971        task_t *task = task_find_by_id(taskid);
    896        
    897972        if (!task) {
    898973                irq_spinlock_unlock(&tasks_lock, true);
    899974                return;
    900975        }
    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        
     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);
    945985        irq_spinlock_lock(&task->answerbox.lock, false);
    946986       
     
    9641004        irq_spinlock_unlock(&task->answerbox.lock, false);
    9651005        irq_spinlock_unlock(&task->lock, true);
     1006
     1007        task_release(task);
    9661008}
    9671009
Note: See TracChangeset for help on using the changeset viewer.