Ignore:
File:
1 edited

Legend:

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

    r6aef742 r287e83f  
    6262
    6363static slab_cache_t *ipc_call_slab;
    64 static slab_cache_t *ipc_answerbox_slab;
    6564
    6665/** Initialize a call structure.
    6766 *
    68  * @param call Call structure to be initialized.
    69  *
     67 * @param call          Call structure to be initialized.
    7068 */
    7169static void _ipc_call_init(call_t *call)
     
    7876
    7977/** Allocate and initialize a call structure.
    80  *
     78 * 
    8179 * The call is initialized, so that the reply will be directed to
    8280 * TASK->answerbox.
    8381 *
    84  * @param flags Parameters for slab_alloc (e.g FRAME_ATOMIC).
    85  *
    86  * @return If flags permit it, return NULL, or initialized kernel
    87  *         call structure.
    88  *
    89  */
    90 call_t *ipc_call_alloc(unsigned int flags)
    91 {
    92         call_t *call = slab_alloc(ipc_call_slab, flags);
     82 * @param flags         Parameters for slab_alloc (e.g FRAME_ATOMIC).
     83 *
     84 * @return              If flags permit it, return NULL, or initialized kernel
     85 *                      call structure.
     86 */
     87call_t *ipc_call_alloc(int flags)
     88{
     89        call_t *call;
     90
     91        call = slab_alloc(ipc_call_slab, flags);
    9392        if (call)
    9493                _ipc_call_init(call);
    95        
     94
    9695        return call;
    9796}
    9897
     98/** Initialize a statically allocated call structure.
     99 *
     100 * @param call          Statically allocated kernel call structure to be
     101 *                      initialized.
     102 */
     103void ipc_call_static_init(call_t *call)
     104{
     105        _ipc_call_init(call);
     106        call->flags |= IPC_CALL_STATIC_ALLOC;
     107}
     108
    99109/** Deallocate a call structure.
    100110 *
    101  * @param call Call structure to be freed.
    102  *
     111 * @param call          Call structure to be freed.
    103112 */
    104113void ipc_call_free(call_t *call)
    105114{
     115        ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
    106116        /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
    107117        if (call->buffer)
     
    112122/** Initialize an answerbox structure.
    113123 *
    114  * @param box  Answerbox structure to be initialized.
    115  * @param task Task to which the answerbox belongs.
    116  *
     124 * @param box           Answerbox structure to be initialized.
     125 * @param task          Task to which the answerbox belongs.
    117126 */
    118127void ipc_answerbox_init(answerbox_t *box, task_t *task)
    119128{
    120         irq_spinlock_initialize(&box->lock, "ipc.box.lock");
    121         irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock");
     129        spinlock_initialize(&box->lock, "ipc_box_lock");
     130        spinlock_initialize(&box->irq_lock, "ipc_box_irqlock");
    122131        waitq_initialize(&box->wq);
    123         link_initialize(&box->sync_box_link);
    124132        list_initialize(&box->connected_phones);
    125133        list_initialize(&box->calls);
     
    133141/** Connect a phone to an answerbox.
    134142 *
    135  * @param phone Initialized phone structure.
    136  * @param box   Initialized answerbox structure.
    137  *
     143 * @param phone         Initialized phone structure.
     144 * @param box           Initialized answerbox structure.
    138145 */
    139146void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    140147{
    141148        mutex_lock(&phone->lock);
    142        
     149
    143150        phone->state = IPC_PHONE_CONNECTED;
    144151        phone->callee = box;
    145        
    146         irq_spinlock_lock(&box->lock, true);
     152
     153        spinlock_lock(&box->lock);
    147154        list_append(&phone->link, &box->connected_phones);
    148         irq_spinlock_unlock(&box->lock, true);
    149        
     155        spinlock_unlock(&box->lock);
     156
    150157        mutex_unlock(&phone->lock);
    151158}
     
    153160/** Initialize a phone structure.
    154161 *
    155  * @param phone Phone structure to be initialized.
    156  *
     162 * @param phone         Phone structure to be initialized.
    157163 */
    158164void ipc_phone_init(phone_t *phone)
     
    166172/** Helper function to facilitate synchronous calls.
    167173 *
    168  * @param phone   Destination kernel phone structure.
    169  * @param request Call structure with request.
    170  *
    171  * @return EOK on success or EINTR if the sleep was interrupted.
    172  *
     174 * @param phone         Destination kernel phone structure.
     175 * @param request       Call structure with request.
     176 *
     177 * @return              EOK on success or EINTR if the sleep was interrupted.
    173178 */
    174179int ipc_call_sync(phone_t *phone, call_t *request)
    175180{
    176         answerbox_t *sync_box = slab_alloc(ipc_answerbox_slab, 0);
    177         ipc_answerbox_init(sync_box, TASK);
    178        
    179         /*
    180          * Put the answerbox on the TASK's list of synchronous answerboxes so
    181          * that it can be cleaned up if the call is interrupted.
    182          */
    183         irq_spinlock_lock(&TASK->lock, true);
    184         list_append(&sync_box->sync_box_link, &TASK->sync_box_head);
    185         irq_spinlock_unlock(&TASK->lock, true);
    186        
     181        answerbox_t sync_box;
     182
     183        ipc_answerbox_init(&sync_box, TASK);
     184
    187185        /* We will receive data in a special box. */
    188         request->callerbox = sync_box;
    189        
     186        request->callerbox = &sync_box;
     187
    190188        ipc_call(phone, request);
    191         if (!ipc_wait_for_call(sync_box, SYNCH_NO_TIMEOUT,
    192             SYNCH_FLAGS_INTERRUPTIBLE)) {
    193                 /* The answerbox and the call will be freed by ipc_cleanup(). */
     189        if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT,
     190            SYNCH_FLAGS_INTERRUPTIBLE))
    194191                return EINTR;
    195         }
    196        
    197         /*
    198          * The answer arrived without interruption so we can remove the
    199          * answerbox from the TASK's list of synchronous answerboxes.
    200          */
    201         irq_spinlock_lock(&TASK->lock, true);
    202         list_remove(&sync_box->sync_box_link);
    203         irq_spinlock_unlock(&TASK->lock, true);
    204        
    205         slab_free(ipc_answerbox_slab, sync_box);
    206192        return EOK;
    207193}
     
    209195/** Answer a message which was not dispatched and is not listed in any queue.
    210196 *
    211  * @param call       Call structure to be answered.
    212  * @param selflocked If true, then TASK->answebox is locked.
    213  *
    214  */
    215 static void _ipc_answer_free_call(call_t *call, bool selflocked)
     197 * @param call          Call structure to be answered.
     198 */
     199static void _ipc_answer_free_call(call_t *call)
    216200{
    217201        answerbox_t *callerbox = call->callerbox;
    218         bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
    219        
    220         /* Count sent answer */
    221         irq_spinlock_lock(&TASK->lock, true);
    222         TASK->ipc_info.answer_sent++;
    223         irq_spinlock_unlock(&TASK->lock, true);
    224        
     202
    225203        call->flags |= IPC_CALL_ANSWERED;
    226        
     204
    227205        if (call->flags & IPC_CALL_FORWARDED) {
    228206                if (call->caller_phone) {
     
    231209                }
    232210        }
    233        
    234         if (do_lock)
    235                 irq_spinlock_lock(&callerbox->lock, true);
    236        
     211
     212        spinlock_lock(&callerbox->lock);
    237213        list_append(&call->link, &callerbox->answers);
    238        
    239         if (do_lock)
    240                 irq_spinlock_unlock(&callerbox->lock, true);
    241        
     214        spinlock_unlock(&callerbox->lock);
    242215        waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
    243216}
     
    245218/** Answer a message which is in a callee queue.
    246219 *
    247  * @param box  Answerbox that is answering the message.
    248  * @param call Modified request that is being sent back.
    249  *
     220 * @param box           Answerbox that is answering the message.
     221 * @param call          Modified request that is being sent back.
    250222 */
    251223void ipc_answer(answerbox_t *box, call_t *call)
    252224{
    253225        /* Remove from active box */
    254         irq_spinlock_lock(&box->lock, true);
     226        spinlock_lock(&box->lock);
    255227        list_remove(&call->link);
    256         irq_spinlock_unlock(&box->lock, true);
    257        
     228        spinlock_unlock(&box->lock);
    258229        /* Send back answer */
    259         _ipc_answer_free_call(call, false);
     230        _ipc_answer_free_call(call);
    260231}
    261232
     
    265236 * message and sending it as a normal answer.
    266237 *
    267  * @param phone Phone structure the call should appear to come from.
    268  * @param call  Call structure to be answered.
    269  * @param err   Return value to be used for the answer.
    270  *
    271  */
    272 void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
     238 * @param phone         Phone structure the call should appear to come from.
     239 * @param call          Call structure to be answered.
     240 * @param err           Return value to be used for the answer.
     241 */
     242void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err)
    273243{
    274244        call->data.phone = phone;
    275245        atomic_inc(&phone->active_calls);
    276246        IPC_SET_RETVAL(call->data, err);
    277         _ipc_answer_free_call(call, false);
     247        _ipc_answer_free_call(call);
    278248}
    279249
    280250/** Unsafe unchecking version of ipc_call.
    281251 *
    282  * @param phone Phone structure the call comes from.
    283  * @param box   Destination answerbox structure.
    284  * @param call  Call structure with request.
    285  *
     252 * @param phone         Phone structure the call comes from.
     253 * @param box           Destination answerbox structure.
     254 * @param call          Call structure with request.
    286255 */
    287256static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    288257{
    289         /* Count sent ipc call */
    290         irq_spinlock_lock(&TASK->lock, true);
    291         TASK->ipc_info.call_sent++;
    292         irq_spinlock_unlock(&TASK->lock, true);
    293        
    294258        if (!(call->flags & IPC_CALL_FORWARDED)) {
    295259                atomic_inc(&phone->active_calls);
    296260                call->data.phone = phone;
    297                 call->data.task = TASK;
    298         }
    299        
    300         irq_spinlock_lock(&box->lock, true);
     261        }
     262
     263        spinlock_lock(&box->lock);
    301264        list_append(&call->link, &box->calls);
    302         irq_spinlock_unlock(&box->lock, true);
    303        
     265        spinlock_unlock(&box->lock);
    304266        waitq_wakeup(&box->wq, WAKEUP_FIRST);
    305267}
     
    307269/** Send an asynchronous request using a phone to an answerbox.
    308270 *
    309  * @param phone Phone structure the call comes from and which is
    310  *              connected to the destination answerbox.
    311  * @param call  Call structure with request.
    312  *
    313  * @return Return 0 on success, ENOENT on error.
    314  *
     271 * @param phone         Phone structure the call comes from and which is
     272 *                      connected to the destination answerbox.
     273 * @param call          Call structure with request.
     274 *
     275 * @return              Return 0 on success, ENOENT on error.
    315276 */
    316277int ipc_call(phone_t *phone, call_t *call)
    317278{
     279        answerbox_t *box;
     280
    318281        mutex_lock(&phone->lock);
    319282        if (phone->state != IPC_PHONE_CONNECTED) {
     
    321284                if (call->flags & IPC_CALL_FORWARDED) {
    322285                        IPC_SET_RETVAL(call->data, EFORWARD);
    323                         _ipc_answer_free_call(call, false);
     286                        _ipc_answer_free_call(call);
    324287                } else {
    325288                        if (phone->state == IPC_PHONE_HUNGUP)
     
    328291                                ipc_backsend_err(phone, call, ENOENT);
    329292                }
    330                
    331293                return ENOENT;
    332294        }
    333        
    334         answerbox_t *box = phone->callee;
     295        box = phone->callee;
    335296        _ipc_call(phone, box, call);
    336297       
     
    344305 * lazily later.
    345306 *
    346  * @param phone Phone structure to be hung up.
    347  *
    348  * @return 0 if the phone is disconnected.
    349  * @return -1 if the phone was already disconnected.
    350  *
     307 * @param phone         Phone structure to be hung up.
     308 *             
     309 * @return              Return 0 if the phone is disconnected.
     310 *                      Return -1 if the phone was already disconnected.
    351311 */
    352312int ipc_phone_hangup(phone_t *phone)
    353313{
     314        answerbox_t *box;
     315        call_t *call;
     316       
    354317        mutex_lock(&phone->lock);
    355318        if (phone->state == IPC_PHONE_FREE ||
     
    359322                return -1;
    360323        }
    361        
    362         answerbox_t *box = phone->callee;
     324        box = phone->callee;
    363325        if (phone->state != IPC_PHONE_SLAMMED) {
    364326                /* Remove myself from answerbox */
    365                 irq_spinlock_lock(&box->lock, true);
     327                spinlock_lock(&box->lock);
    366328                list_remove(&phone->link);
    367                 irq_spinlock_unlock(&box->lock, true);
    368                
    369                 call_t *call = ipc_call_alloc(0);
    370                 IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     329                spinlock_unlock(&box->lock);
     330
     331                call = ipc_call_alloc(0);
     332                IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
    371333                call->flags |= IPC_CALL_DISCARD_ANSWER;
    372334                _ipc_call(phone, box, call);
    373335        }
    374        
     336
    375337        phone->state = IPC_PHONE_HUNGUP;
    376338        mutex_unlock(&phone->lock);
    377        
     339
    378340        return 0;
    379341}
     
    381343/** Forwards call from one answerbox to another one.
    382344 *
    383  * @param call     Call structure to be redirected.
    384  * @param newphone Phone structure to target answerbox.
    385  * @param oldbox   Old answerbox structure.
    386  * @param mode     Flags that specify mode of the forward operation.
    387  *
    388  * @return 0 if forwarding succeeded or an error code if
    389  *         there was an error.
    390  *
     345 * @param call          Call structure to be redirected.
     346 * @param newphone      Phone structure to target answerbox.
     347 * @param oldbox        Old answerbox structure.
     348 * @param mode          Flags that specify mode of the forward operation.
     349 *
     350 * @return              Return 0 if forwarding succeeded or an error code if
     351 *                      there was error.
     352 * 
    391353 * The return value serves only as an information for the forwarder,
    392354 * the original caller is notified automatically with EFORWARD.
    393  *
    394  */
    395 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox,
    396     unsigned int mode)
    397 {
    398         /* Count forwarded calls */
    399         irq_spinlock_lock(&TASK->lock, true);
    400         TASK->ipc_info.forwarded++;
    401         irq_spinlock_pass(&TASK->lock, &oldbox->lock);
     355 */
     356int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode)
     357{
     358        spinlock_lock(&oldbox->lock);
    402359        list_remove(&call->link);
    403         irq_spinlock_unlock(&oldbox->lock, true);
    404        
     360        spinlock_unlock(&oldbox->lock);
     361
    405362        if (mode & IPC_FF_ROUTE_FROM_ME) {
    406363                if (!call->caller_phone)
    407364                        call->caller_phone = call->data.phone;
    408365                call->data.phone = newphone;
    409                 call->data.task = TASK;
    410         }
    411        
     366        }
     367
    412368        return ipc_call(newphone, call);
    413369}
     
    416372/** Wait for a phone call.
    417373 *
    418  * @param box   Answerbox expecting the call.
    419  * @param usec  Timeout in microseconds. See documentation for
    420  *              waitq_sleep_timeout() for decription of its special
    421  *              meaning.
    422  * @param flags Select mode of sleep operation. See documentation for
    423  *              waitq_sleep_timeout() for description of its special
    424  *              meaning.
    425  *
    426  * @return Recived call structure or NULL.
    427  *
     374 * @param box           Answerbox expecting the call.
     375 * @param usec          Timeout in microseconds. See documentation for
     376 *                      waitq_sleep_timeout() for decription of its special
     377 *                      meaning.
     378 * @param flags         Select mode of sleep operation. See documentation for
     379 *                      waitq_sleep_timeout() for description of its special
     380 *                      meaning.
     381 * @return              Recived call structure or NULL.
     382 *
    428383 * To distinguish between a call and an answer, have a look at call->flags.
    429  *
    430  */
    431 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags)
     384 */
     385call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags)
    432386{
    433387        call_t *request;
    434         uint64_t irq_cnt = 0;
    435         uint64_t answer_cnt = 0;
    436         uint64_t call_cnt = 0;
     388        ipl_t ipl;
    437389        int rc;
    438        
     390
    439391restart:
    440392        rc = waitq_sleep_timeout(&box->wq, usec, flags);
     
    442394                return NULL;
    443395       
    444         irq_spinlock_lock(&box->lock, true);
     396        spinlock_lock(&box->lock);
    445397        if (!list_empty(&box->irq_notifs)) {
    446                 /* Count received IRQ notification */
    447                 irq_cnt++;
    448                
    449                 irq_spinlock_lock(&box->irq_lock, false);
    450                
     398                ipl = interrupts_disable();
     399                spinlock_lock(&box->irq_lock);
     400
    451401                request = list_get_instance(box->irq_notifs.next, call_t, link);
    452402                list_remove(&request->link);
    453                
    454                 irq_spinlock_unlock(&box->irq_lock, false);
     403
     404                spinlock_unlock(&box->irq_lock);
     405                interrupts_restore(ipl);
    455406        } else if (!list_empty(&box->answers)) {
    456                 /* Count received answer */
    457                 answer_cnt++;
    458                
    459407                /* Handle asynchronous answers */
    460408                request = list_get_instance(box->answers.next, call_t, link);
     
    462410                atomic_dec(&request->data.phone->active_calls);
    463411        } else if (!list_empty(&box->calls)) {
    464                 /* Count received call */
    465                 call_cnt++;
    466                
    467412                /* Handle requests */
    468413                request = list_get_instance(box->calls.next, call_t, link);
    469414                list_remove(&request->link);
    470                
    471415                /* Append request to dispatch queue */
    472416                list_append(&request->link, &box->dispatched_calls);
    473417        } else {
    474418                /* This can happen regularly after ipc_cleanup */
    475                 irq_spinlock_unlock(&box->lock, true);
     419                spinlock_unlock(&box->lock);
    476420                goto restart;
    477421        }
    478        
    479         irq_spinlock_pass(&box->lock, &TASK->lock);
    480        
    481         TASK->ipc_info.irq_notif_received += irq_cnt;
    482         TASK->ipc_info.answer_received += answer_cnt;
    483         TASK->ipc_info.call_received += call_cnt;
    484        
    485         irq_spinlock_unlock(&TASK->lock, true);
    486        
     422        spinlock_unlock(&box->lock);
    487423        return request;
    488424}
     
    490426/** Answer all calls from list with EHANGUP answer.
    491427 *
    492  * @param lst Head of the list to be cleaned up.
    493  *
     428 * @param lst           Head of the list to be cleaned up.
    494429 */
    495430void ipc_cleanup_call_list(link_t *lst)
    496431{
     432        call_t *call;
     433
    497434        while (!list_empty(lst)) {
    498                 call_t *call = list_get_instance(lst->next, call_t, link);
     435                call = list_get_instance(lst->next, call_t, link);
    499436                if (call->buffer)
    500437                        free(call->buffer);
    501                
    502438                list_remove(&call->link);
    503                
     439
    504440                IPC_SET_RETVAL(call->data, EHANGUP);
    505                 _ipc_answer_free_call(call, true);
     441                _ipc_answer_free_call(call);
    506442        }
    507443}
     
    509445/** Disconnects all phones connected to an answerbox.
    510446 *
    511  * @param box        Answerbox to disconnect phones from.
    512  * @param notify_box If true, the answerbox will get a hangup message for
    513  *                   each disconnected phone.
    514  *
     447 * @param box           Answerbox to disconnect phones from.
     448 * @param notify_box    If true, the answerbox will get a hangup message for
     449 *                      each disconnected phone.
    515450 */
    516451void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
     
    518453        phone_t *phone;
    519454        DEADLOCK_PROBE_INIT(p_phonelck);
    520        
    521         call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
    522        
     455        ipl_t ipl;
     456        call_t *call;
     457
     458        call = notify_box ? ipc_call_alloc(0) : NULL;
     459
    523460        /* Disconnect all phones connected to our answerbox */
    524461restart_phones:
    525         irq_spinlock_lock(&box->lock, true);
     462        ipl = interrupts_disable();
     463        spinlock_lock(&box->lock);
    526464        while (!list_empty(&box->connected_phones)) {
    527465                phone = list_get_instance(box->connected_phones.next,
    528466                    phone_t, link);
    529467                if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
    530                         irq_spinlock_unlock(&box->lock, true);
     468                        spinlock_unlock(&box->lock);
     469                        interrupts_restore(ipl);
    531470                        DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
    532471                        goto restart_phones;
     
    535474                /* Disconnect phone */
    536475                ASSERT(phone->state == IPC_PHONE_CONNECTED);
    537                
     476
    538477                list_remove(&phone->link);
    539478                phone->state = IPC_PHONE_SLAMMED;
    540                
     479
    541480                if (notify_box) {
    542481                        mutex_unlock(&phone->lock);
    543                         irq_spinlock_unlock(&box->lock, true);
    544                        
     482                        spinlock_unlock(&box->lock);
     483                        interrupts_restore(ipl);
     484
    545485                        /*
    546486                         * Send one message to the answerbox for each
     
    549489                         * disconnected.
    550490                         */
    551                         IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     491                        IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
    552492                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    553493                        _ipc_call(phone, box, call);
    554                        
     494
    555495                        /* Allocate another call in advance */
    556496                        call = ipc_call_alloc(0);
    557                        
     497
    558498                        /* Must start again */
    559499                        goto restart_phones;
    560500                }
    561                
     501
    562502                mutex_unlock(&phone->lock);
    563503        }
    564        
    565         irq_spinlock_unlock(&box->lock, true);
    566        
     504
     505        spinlock_unlock(&box->lock);
     506        interrupts_restore(ipl);
     507
    567508        /* Free unused call */
    568509        if (call)
     
    570511}
    571512
    572 /** Clean up all IPC communication of the current task.
     513/** Cleans up all IPC communication of the current task.
    573514 *
    574515 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
    575516 * have to change it as well if you want to cleanup other tasks than TASK.
    576  *
    577517 */
    578518void ipc_cleanup(void)
    579519{
     520        int i;
     521        call_t *call;
     522
    580523        /* Disconnect all our phones ('ipc_phone_hangup') */
    581         size_t i;
    582524        for (i = 0; i < IPC_MAX_PHONES; i++)
    583525                ipc_phone_hangup(&TASK->phones[i]);
    584        
     526
    585527        /* Unsubscribe from any event notifications. */
    586528        event_cleanup_answerbox(&TASK->answerbox);
    587        
     529
    588530        /* Disconnect all connected irqs */
    589531        ipc_irq_cleanup(&TASK->answerbox);
    590        
     532
    591533        /* Disconnect all phones connected to our regular answerbox */
    592534        ipc_answerbox_slam_phones(&TASK->answerbox, false);
    593        
     535
    594536#ifdef CONFIG_UDEBUG
    595537        /* Clean up kbox thread and communications */
    596538        ipc_kbox_cleanup();
    597539#endif
    598        
     540
    599541        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    600         irq_spinlock_lock(&TASK->answerbox.lock, true);
     542        spinlock_lock(&TASK->answerbox.lock);
    601543        ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
    602544        ipc_cleanup_call_list(&TASK->answerbox.calls);
    603         irq_spinlock_unlock(&TASK->answerbox.lock, true);
     545        spinlock_unlock(&TASK->answerbox.lock);
    604546       
    605         /* Wait for all answers to interrupted synchronous calls to arrive */
    606         ipl_t ipl = interrupts_disable();
    607         while (!list_empty(&TASK->sync_box_head)) {
    608                 answerbox_t *box = list_get_instance(TASK->sync_box_head.next,
    609                     answerbox_t, sync_box_link);
    610                
    611                 list_remove(&box->sync_box_link);
    612                 call_t *call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT,
    613                     SYNCH_FLAGS_NONE);
    614                 ipc_call_free(call);
    615                 slab_free(ipc_answerbox_slab, box);
    616         }
    617         interrupts_restore(ipl);
    618        
    619         /* Wait for all answers to asynchronous calls to arrive */
    620         while (true) {
    621                 /*
    622                  * Go through all phones, until they are all FREE
    623                  * Locking is not needed, no one else should modify
    624                  * it when we are in cleanup
    625                  */
     547        /* Wait for all async answers to arrive */
     548        while (1) {
     549                /* Go through all phones, until all are FREE... */
     550                /* Locking not needed, no one else should modify
     551                 * it, when we are in cleanup */
    626552                for (i = 0; i < IPC_MAX_PHONES; i++) {
    627553                        if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
    628                             atomic_get(&TASK->phones[i].active_calls) == 0) {
     554                            atomic_get(&TASK->phones[i].active_calls) == 0)
    629555                                TASK->phones[i].state = IPC_PHONE_FREE;
    630                                 TASK->phones[i].callee = NULL;
    631                         }
    632556                       
    633                         /*
    634                          * Just for sure, we might have had some
    635                          * IPC_PHONE_CONNECTING phones
    636                          */
     557                        /* Just for sure, we might have had some
     558                         * IPC_PHONE_CONNECTING phones */
    637559                        if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
    638560                                ipc_phone_hangup(&TASK->phones[i]);
    639                        
    640                         /*
    641                          * If the hangup succeeded, it has sent a HANGUP
     561                        /* If the hangup succeeded, it has sent a HANGUP
    642562                         * message, the IPC is now in HUNGUP state, we
    643                          * wait for the reply to come
    644                          */
     563                         * wait for the reply to come */
    645564                       
    646565                        if (TASK->phones[i].state != IPC_PHONE_FREE)
    647566                                break;
    648567                }
    649                
    650                 /* Got into cleanup */
     568                /* Voila, got into cleanup */
    651569                if (i == IPC_MAX_PHONES)
    652570                        break;
    653571               
    654                 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
     572                call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    655573                    SYNCH_FLAGS_NONE);
    656574                ASSERT((call->flags & IPC_CALL_ANSWERED) ||
    657575                    (call->flags & IPC_CALL_NOTIF));
     576                ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
    658577               
     578                /*
     579                 * Record the receipt of this call in the current task's counter
     580                 * of active calls. IPC_M_PHONE_HUNGUP calls do not contribute
     581                 * to this counter so do not record answers to them either.
     582                 */
     583                if (!(call->flags & IPC_CALL_DISCARD_ANSWER))
     584                        atomic_dec(&TASK->active_calls);
    659585                ipc_call_free(call);
    660586        }
    661587}
    662588
    663 /** Initilize IPC subsystem
    664  *
    665  */
     589
     590/** Initilize IPC subsystem */
    666591void ipc_init(void)
    667592{
    668593        ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL,
    669594            NULL, 0);
    670         ipc_answerbox_slab = slab_cache_create("ipc_answerbox",
    671             sizeof(answerbox_t), 0, NULL, NULL, 0);
    672 }
     595}
     596
    673597
    674598/** List answerbox contents.
    675599 *
    676  * @param taskid Task ID.
    677  *
     600 * @param taskid        Task ID.
    678601 */
    679602void ipc_print_task(task_id_t taskid)
    680603{
    681         irq_spinlock_lock(&tasks_lock, true);
    682         task_t *task = task_find_by_id(taskid);
     604        task_t *task;
     605        int i;
     606        call_t *call;
     607        link_t *tmp;
    683608       
    684         if (!task) {
    685                 irq_spinlock_unlock(&tasks_lock, true);
     609        spinlock_lock(&tasks_lock);
     610        task = task_find_by_id(taskid);
     611        if (task)
     612                spinlock_lock(&task->lock);
     613        spinlock_unlock(&tasks_lock);
     614        if (!task)
    686615                return;
    687         }
    688        
    689         /* Hand-over-hand locking */
    690         irq_spinlock_exchange(&tasks_lock, &task->lock);
    691        
    692         printf("[phone id] [calls] [state\n");
    693        
    694         size_t i;
     616
     617        /* Print opened phones & details */
     618        printf("PHONE:\n");
    695619        for (i = 0; i < IPC_MAX_PHONES; i++) {
    696620                if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
    697                         printf("%-10zu (mutex busy)\n", i);
     621                        printf("%d: mutex busy\n", i);
    698622                        continue;
    699623                }
    700                
    701624                if (task->phones[i].state != IPC_PHONE_FREE) {
    702                         printf("%-10zu %7" PRIun " ", i,
    703                             atomic_get(&task->phones[i].active_calls));
    704                        
     625                        printf("%d: ", i);
    705626                        switch (task->phones[i].state) {
    706627                        case IPC_PHONE_CONNECTING:
    707                                 printf("connecting");
     628                                printf("connecting ");
    708629                                break;
    709630                        case IPC_PHONE_CONNECTED:
    710                                 printf("connected to %" PRIu64 " (%s)",
    711                                     task->phones[i].callee->task->taskid,
    712                                     task->phones[i].callee->task->name);
     631                                printf("connected to: %p ",
     632                                       task->phones[i].callee);
    713633                                break;
    714634                        case IPC_PHONE_SLAMMED:
    715                                 printf("slammed by %p",
    716                                     task->phones[i].callee);
     635                                printf("slammed by: %p ",
     636                                       task->phones[i].callee);
    717637                                break;
    718638                        case IPC_PHONE_HUNGUP:
    719                                 printf("hung up by %p",
    720                                     task->phones[i].callee);
     639                                printf("hung up - was: %p ",
     640                                       task->phones[i].callee);
    721641                                break;
    722642                        default:
    723643                                break;
    724644                        }
    725                        
    726                         printf("\n");
     645                        printf("active: %ld\n",
     646                            atomic_get(&task->phones[i].active_calls));
    727647                }
    728                
    729648                mutex_unlock(&task->phones[i].lock);
    730649        }
    731        
    732         irq_spinlock_lock(&task->answerbox.lock, false);
    733        
    734 #ifdef __32_BITS__
    735         printf("[call id ] [method] [arg1] [arg2] [arg3] [arg4] [arg5]"
    736             " [flags] [sender\n");
    737 #endif
    738        
    739 #ifdef __64_BITS__
    740         printf("[call id         ] [method] [arg1] [arg2] [arg3] [arg4]"
    741             " [arg5] [flags] [sender\n");
    742 #endif
    743        
    744         link_t *cur;
    745        
    746         printf(" --- incomming calls ---\n");
    747         for (cur = task->answerbox.calls.next; cur != &task->answerbox.calls;
    748             cur = cur->next) {
    749                 call_t *call = list_get_instance(cur, call_t, link);
    750                
    751 #ifdef __32_BITS__
    752                 printf("%10p ", call);
    753 #endif
    754                
    755 #ifdef __64_BITS__
    756                 printf("%18p ", call);
    757 #endif
    758                
    759                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    760                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    761                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     650
     651
     652        /* Print answerbox - calls */
     653        spinlock_lock(&task->answerbox.lock);
     654        printf("ABOX - CALLS:\n");
     655        for (tmp = task->answerbox.calls.next; tmp != &task->answerbox.calls;
     656            tmp = tmp->next) {
     657                call = list_get_instance(tmp, call_t, link);
     658                printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
     659                    " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
     660                    " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
     661                    call->sender->taskid,
     662                    IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
    762663                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    763664                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    764                     call->flags, call->sender->taskid, call->sender->name);
    765         }
    766        
    767         printf(" --- dispatched calls ---\n");
    768         for (cur = task->answerbox.dispatched_calls.next;
    769             cur != &task->answerbox.dispatched_calls;
    770             cur = cur->next) {
    771                 call_t *call = list_get_instance(cur, call_t, link);
    772                
    773 #ifdef __32_BITS__
    774                 printf("%10p ", call);
    775 #endif
    776                
    777 #ifdef __64_BITS__
    778                 printf("%18p ", call);
    779 #endif
    780                
    781                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    782                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    783                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     665                    call->flags);
     666        }
     667        /* Print answerbox - calls */
     668        printf("ABOX - DISPATCHED CALLS:\n");
     669        for (tmp = task->answerbox.dispatched_calls.next;
     670            tmp != &task->answerbox.dispatched_calls;
     671            tmp = tmp->next) {
     672                call = list_get_instance(tmp, call_t, link);
     673                printf("Callid: %p Srctask:%" PRIu64 " M:%" PRIun
     674                    " A1:%" PRIun " A2:%" PRIun " A3:%" PRIun
     675                    " A4:%" PRIun " A5:%" PRIun " Flags:%x\n", call,
     676                    call->sender->taskid,
     677                    IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
    784678                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    785679                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    786                     call->flags, call->sender->taskid, call->sender->name);
    787         }
    788        
    789         printf(" --- incoming answers ---\n");
    790         for (cur = task->answerbox.answers.next;
    791             cur != &task->answerbox.answers;
    792             cur = cur->next) {
    793                 call_t *call = list_get_instance(cur, call_t, link);
    794                
    795 #ifdef __32_BITS__
    796                 printf("%10p ", call);
    797 #endif
    798                
    799 #ifdef __64_BITS__
    800                 printf("%18p ", call);
    801 #endif
    802                
    803                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    804                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    805                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     680                    call->flags);
     681        }
     682        /* Print answerbox - calls */
     683        printf("ABOX - ANSWERS:\n");
     684        for (tmp = task->answerbox.answers.next;
     685            tmp != &task->answerbox.answers;
     686            tmp = tmp->next) {
     687                call = list_get_instance(tmp, call_t, link);
     688                printf("Callid:%p M:%" PRIun " A1:%" PRIun " A2:%" PRIun
     689                    " A3:%" PRIun " A4:%" PRIun " A5:%" PRIun " Flags:%x\n",
     690                    call, IPC_GET_METHOD(call->data), IPC_GET_ARG1(call->data),
    806691                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    807692                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    808                     call->flags, call->sender->taskid, call->sender->name);
    809         }
    810        
    811         irq_spinlock_unlock(&task->answerbox.lock, false);
    812         irq_spinlock_unlock(&task->lock, true);
     693                    call->flags);
     694        }
     695
     696        spinlock_unlock(&task->answerbox.lock);
     697        spinlock_unlock(&task->lock);
    813698}
    814699
Note: See TracChangeset for help on using the changeset viewer.