Ignore:
File:
1 edited

Legend:

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

    r287e83f r6aef742  
    6262
    6363static slab_cache_t *ipc_call_slab;
     64static slab_cache_t *ipc_answerbox_slab;
    6465
    6566/** Initialize a call structure.
    6667 *
    67  * @param call          Call structure to be initialized.
     68 * @param call Call structure to be initialized.
     69 *
    6870 */
    6971static void _ipc_call_init(call_t *call)
     
    7678
    7779/** Allocate and initialize a call structure.
    78  * 
     80 *
    7981 * The call is initialized, so that the reply will be directed to
    8082 * TASK->answerbox.
    8183 *
    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  */
    87 call_t *ipc_call_alloc(int flags)
    88 {
    89         call_t *call;
    90 
    91         call = slab_alloc(ipc_call_slab, flags);
     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 */
     90call_t *ipc_call_alloc(unsigned int flags)
     91{
     92        call_t *call = slab_alloc(ipc_call_slab, flags);
    9293        if (call)
    9394                _ipc_call_init(call);
    94 
     95       
    9596        return call;
    9697}
    9798
    98 /** Initialize a statically allocated call structure.
    99  *
    100  * @param call          Statically allocated kernel call structure to be
    101  *                      initialized.
    102  */
    103 void ipc_call_static_init(call_t *call)
    104 {
    105         _ipc_call_init(call);
    106         call->flags |= IPC_CALL_STATIC_ALLOC;
    107 }
    108 
    10999/** Deallocate a call structure.
    110100 *
    111  * @param call          Call structure to be freed.
     101 * @param call Call structure to be freed.
     102 *
    112103 */
    113104void ipc_call_free(call_t *call)
    114105{
    115         ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
    116106        /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
    117107        if (call->buffer)
     
    122112/** Initialize an answerbox structure.
    123113 *
    124  * @param box           Answerbox structure to be initialized.
    125  * @param task          Task to which the answerbox belongs.
     114 * @param box  Answerbox structure to be initialized.
     115 * @param task Task to which the answerbox belongs.
     116 *
    126117 */
    127118void ipc_answerbox_init(answerbox_t *box, task_t *task)
    128119{
    129         spinlock_initialize(&box->lock, "ipc_box_lock");
    130         spinlock_initialize(&box->irq_lock, "ipc_box_irqlock");
     120        irq_spinlock_initialize(&box->lock, "ipc.box.lock");
     121        irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock");
    131122        waitq_initialize(&box->wq);
     123        link_initialize(&box->sync_box_link);
    132124        list_initialize(&box->connected_phones);
    133125        list_initialize(&box->calls);
     
    141133/** Connect a phone to an answerbox.
    142134 *
    143  * @param phone         Initialized phone structure.
    144  * @param box           Initialized answerbox structure.
     135 * @param phone Initialized phone structure.
     136 * @param box   Initialized answerbox structure.
     137 *
    145138 */
    146139void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    147140{
    148141        mutex_lock(&phone->lock);
    149 
     142       
    150143        phone->state = IPC_PHONE_CONNECTED;
    151144        phone->callee = box;
    152 
    153         spinlock_lock(&box->lock);
     145       
     146        irq_spinlock_lock(&box->lock, true);
    154147        list_append(&phone->link, &box->connected_phones);
    155         spinlock_unlock(&box->lock);
    156 
     148        irq_spinlock_unlock(&box->lock, true);
     149       
    157150        mutex_unlock(&phone->lock);
    158151}
     
    160153/** Initialize a phone structure.
    161154 *
    162  * @param phone         Phone structure to be initialized.
     155 * @param phone Phone structure to be initialized.
     156 *
    163157 */
    164158void ipc_phone_init(phone_t *phone)
     
    172166/** Helper function to facilitate synchronous calls.
    173167 *
    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.
     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 *
    178173 */
    179174int ipc_call_sync(phone_t *phone, call_t *request)
    180175{
    181         answerbox_t sync_box;
    182 
    183         ipc_answerbox_init(&sync_box, TASK);
    184 
     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       
    185187        /* We will receive data in a special box. */
    186         request->callerbox = &sync_box;
    187 
     188        request->callerbox = sync_box;
     189       
    188190        ipc_call(phone, request);
    189         if (!ipc_wait_for_call(&sync_box, SYNCH_NO_TIMEOUT,
    190             SYNCH_FLAGS_INTERRUPTIBLE))
     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(). */
    191194                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);
    192206        return EOK;
    193207}
     
    195209/** Answer a message which was not dispatched and is not listed in any queue.
    196210 *
    197  * @param call          Call structure to be answered.
    198  */
    199 static void _ipc_answer_free_call(call_t *call)
     211 * @param call       Call structure to be answered.
     212 * @param selflocked If true, then TASK->answebox is locked.
     213 *
     214 */
     215static void _ipc_answer_free_call(call_t *call, bool selflocked)
    200216{
    201217        answerbox_t *callerbox = call->callerbox;
    202 
     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       
    203225        call->flags |= IPC_CALL_ANSWERED;
    204 
     226       
    205227        if (call->flags & IPC_CALL_FORWARDED) {
    206228                if (call->caller_phone) {
     
    209231                }
    210232        }
    211 
    212         spinlock_lock(&callerbox->lock);
     233       
     234        if (do_lock)
     235                irq_spinlock_lock(&callerbox->lock, true);
     236       
    213237        list_append(&call->link, &callerbox->answers);
    214         spinlock_unlock(&callerbox->lock);
     238       
     239        if (do_lock)
     240                irq_spinlock_unlock(&callerbox->lock, true);
     241       
    215242        waitq_wakeup(&callerbox->wq, WAKEUP_FIRST);
    216243}
     
    218245/** Answer a message which is in a callee queue.
    219246 *
    220  * @param box           Answerbox that is answering the message.
    221  * @param call          Modified request that is being sent back.
     247 * @param box  Answerbox that is answering the message.
     248 * @param call Modified request that is being sent back.
     249 *
    222250 */
    223251void ipc_answer(answerbox_t *box, call_t *call)
    224252{
    225253        /* Remove from active box */
    226         spinlock_lock(&box->lock);
     254        irq_spinlock_lock(&box->lock, true);
    227255        list_remove(&call->link);
    228         spinlock_unlock(&box->lock);
     256        irq_spinlock_unlock(&box->lock, true);
     257       
    229258        /* Send back answer */
    230         _ipc_answer_free_call(call);
     259        _ipc_answer_free_call(call, false);
    231260}
    232261
     
    236265 * message and sending it as a normal answer.
    237266 *
    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  */
    242 void ipc_backsend_err(phone_t *phone, call_t *call, unative_t err)
     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 */
     272void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    243273{
    244274        call->data.phone = phone;
    245275        atomic_inc(&phone->active_calls);
    246276        IPC_SET_RETVAL(call->data, err);
    247         _ipc_answer_free_call(call);
     277        _ipc_answer_free_call(call, false);
    248278}
    249279
    250280/** Unsafe unchecking version of ipc_call.
    251281 *
    252  * @param phone         Phone structure the call comes from.
    253  * @param box           Destination answerbox structure.
    254  * @param call          Call structure with request.
     282 * @param phone Phone structure the call comes from.
     283 * @param box   Destination answerbox structure.
     284 * @param call  Call structure with request.
     285 *
    255286 */
    256287static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    257288{
     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       
    258294        if (!(call->flags & IPC_CALL_FORWARDED)) {
    259295                atomic_inc(&phone->active_calls);
    260296                call->data.phone = phone;
    261         }
    262 
    263         spinlock_lock(&box->lock);
     297                call->data.task = TASK;
     298        }
     299       
     300        irq_spinlock_lock(&box->lock, true);
    264301        list_append(&call->link, &box->calls);
    265         spinlock_unlock(&box->lock);
     302        irq_spinlock_unlock(&box->lock, true);
     303       
    266304        waitq_wakeup(&box->wq, WAKEUP_FIRST);
    267305}
     
    269307/** Send an asynchronous request using a phone to an answerbox.
    270308 *
    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.
     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 *
    276315 */
    277316int ipc_call(phone_t *phone, call_t *call)
    278317{
    279         answerbox_t *box;
    280 
    281318        mutex_lock(&phone->lock);
    282319        if (phone->state != IPC_PHONE_CONNECTED) {
     
    284321                if (call->flags & IPC_CALL_FORWARDED) {
    285322                        IPC_SET_RETVAL(call->data, EFORWARD);
    286                         _ipc_answer_free_call(call);
     323                        _ipc_answer_free_call(call, false);
    287324                } else {
    288325                        if (phone->state == IPC_PHONE_HUNGUP)
     
    291328                                ipc_backsend_err(phone, call, ENOENT);
    292329                }
     330               
    293331                return ENOENT;
    294332        }
    295         box = phone->callee;
     333       
     334        answerbox_t *box = phone->callee;
    296335        _ipc_call(phone, box, call);
    297336       
     
    305344 * lazily later.
    306345 *
    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.
     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 *
    311351 */
    312352int ipc_phone_hangup(phone_t *phone)
    313353{
    314         answerbox_t *box;
    315         call_t *call;
    316        
    317354        mutex_lock(&phone->lock);
    318355        if (phone->state == IPC_PHONE_FREE ||
     
    322359                return -1;
    323360        }
    324         box = phone->callee;
     361       
     362        answerbox_t *box = phone->callee;
    325363        if (phone->state != IPC_PHONE_SLAMMED) {
    326364                /* Remove myself from answerbox */
    327                 spinlock_lock(&box->lock);
     365                irq_spinlock_lock(&box->lock, true);
    328366                list_remove(&phone->link);
    329                 spinlock_unlock(&box->lock);
    330 
    331                 call = ipc_call_alloc(0);
    332                 IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
     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);
    333371                call->flags |= IPC_CALL_DISCARD_ANSWER;
    334372                _ipc_call(phone, box, call);
    335373        }
    336 
     374       
    337375        phone->state = IPC_PHONE_HUNGUP;
    338376        mutex_unlock(&phone->lock);
    339 
     377       
    340378        return 0;
    341379}
     
    343381/** Forwards call from one answerbox to another one.
    344382 *
    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  * 
     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 *
    353391 * The return value serves only as an information for the forwarder,
    354392 * the original caller is notified automatically with EFORWARD.
    355  */
    356 int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox, int mode)
    357 {
    358         spinlock_lock(&oldbox->lock);
     393 *
     394 */
     395int 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);
    359402        list_remove(&call->link);
    360         spinlock_unlock(&oldbox->lock);
    361 
     403        irq_spinlock_unlock(&oldbox->lock, true);
     404       
    362405        if (mode & IPC_FF_ROUTE_FROM_ME) {
    363406                if (!call->caller_phone)
    364407                        call->caller_phone = call->data.phone;
    365408                call->data.phone = newphone;
    366         }
    367 
     409                call->data.task = TASK;
     410        }
     411       
    368412        return ipc_call(newphone, call);
    369413}
     
    372416/** Wait for a phone call.
    373417 *
    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  *
     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 *
    383428 * To distinguish between a call and an answer, have a look at call->flags.
    384  */
    385 call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, int flags)
     429 *
     430 */
     431call_t *ipc_wait_for_call(answerbox_t *box, uint32_t usec, unsigned int flags)
    386432{
    387433        call_t *request;
    388         ipl_t ipl;
     434        uint64_t irq_cnt = 0;
     435        uint64_t answer_cnt = 0;
     436        uint64_t call_cnt = 0;
    389437        int rc;
    390 
     438       
    391439restart:
    392440        rc = waitq_sleep_timeout(&box->wq, usec, flags);
     
    394442                return NULL;
    395443       
    396         spinlock_lock(&box->lock);
     444        irq_spinlock_lock(&box->lock, true);
    397445        if (!list_empty(&box->irq_notifs)) {
    398                 ipl = interrupts_disable();
    399                 spinlock_lock(&box->irq_lock);
    400 
     446                /* Count received IRQ notification */
     447                irq_cnt++;
     448               
     449                irq_spinlock_lock(&box->irq_lock, false);
     450               
    401451                request = list_get_instance(box->irq_notifs.next, call_t, link);
    402452                list_remove(&request->link);
    403 
    404                 spinlock_unlock(&box->irq_lock);
    405                 interrupts_restore(ipl);
     453               
     454                irq_spinlock_unlock(&box->irq_lock, false);
    406455        } else if (!list_empty(&box->answers)) {
     456                /* Count received answer */
     457                answer_cnt++;
     458               
    407459                /* Handle asynchronous answers */
    408460                request = list_get_instance(box->answers.next, call_t, link);
     
    410462                atomic_dec(&request->data.phone->active_calls);
    411463        } else if (!list_empty(&box->calls)) {
     464                /* Count received call */
     465                call_cnt++;
     466               
    412467                /* Handle requests */
    413468                request = list_get_instance(box->calls.next, call_t, link);
    414469                list_remove(&request->link);
     470               
    415471                /* Append request to dispatch queue */
    416472                list_append(&request->link, &box->dispatched_calls);
    417473        } else {
    418474                /* This can happen regularly after ipc_cleanup */
    419                 spinlock_unlock(&box->lock);
     475                irq_spinlock_unlock(&box->lock, true);
    420476                goto restart;
    421477        }
    422         spinlock_unlock(&box->lock);
     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       
    423487        return request;
    424488}
     
    426490/** Answer all calls from list with EHANGUP answer.
    427491 *
    428  * @param lst           Head of the list to be cleaned up.
     492 * @param lst Head of the list to be cleaned up.
     493 *
    429494 */
    430495void ipc_cleanup_call_list(link_t *lst)
    431496{
    432         call_t *call;
    433 
    434497        while (!list_empty(lst)) {
    435                 call = list_get_instance(lst->next, call_t, link);
     498                call_t *call = list_get_instance(lst->next, call_t, link);
    436499                if (call->buffer)
    437500                        free(call->buffer);
     501               
    438502                list_remove(&call->link);
    439 
     503               
    440504                IPC_SET_RETVAL(call->data, EHANGUP);
    441                 _ipc_answer_free_call(call);
     505                _ipc_answer_free_call(call, true);
    442506        }
    443507}
     
    445509/** Disconnects all phones connected to an answerbox.
    446510 *
    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.
     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 *
    450515 */
    451516void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box)
     
    453518        phone_t *phone;
    454519        DEADLOCK_PROBE_INIT(p_phonelck);
    455         ipl_t ipl;
    456         call_t *call;
    457 
    458         call = notify_box ? ipc_call_alloc(0) : NULL;
    459 
     520       
     521        call_t *call = notify_box ? ipc_call_alloc(0) : NULL;
     522       
    460523        /* Disconnect all phones connected to our answerbox */
    461524restart_phones:
    462         ipl = interrupts_disable();
    463         spinlock_lock(&box->lock);
     525        irq_spinlock_lock(&box->lock, true);
    464526        while (!list_empty(&box->connected_phones)) {
    465527                phone = list_get_instance(box->connected_phones.next,
    466528                    phone_t, link);
    467529                if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
    468                         spinlock_unlock(&box->lock);
    469                         interrupts_restore(ipl);
     530                        irq_spinlock_unlock(&box->lock, true);
    470531                        DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD);
    471532                        goto restart_phones;
     
    474535                /* Disconnect phone */
    475536                ASSERT(phone->state == IPC_PHONE_CONNECTED);
    476 
     537               
    477538                list_remove(&phone->link);
    478539                phone->state = IPC_PHONE_SLAMMED;
    479 
     540               
    480541                if (notify_box) {
    481542                        mutex_unlock(&phone->lock);
    482                         spinlock_unlock(&box->lock);
    483                         interrupts_restore(ipl);
    484 
     543                        irq_spinlock_unlock(&box->lock, true);
     544                       
    485545                        /*
    486546                         * Send one message to the answerbox for each
     
    489549                         * disconnected.
    490550                         */
    491                         IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP);
     551                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
    492552                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    493553                        _ipc_call(phone, box, call);
    494 
     554                       
    495555                        /* Allocate another call in advance */
    496556                        call = ipc_call_alloc(0);
    497 
     557                       
    498558                        /* Must start again */
    499559                        goto restart_phones;
    500560                }
    501 
     561               
    502562                mutex_unlock(&phone->lock);
    503563        }
    504 
    505         spinlock_unlock(&box->lock);
    506         interrupts_restore(ipl);
    507 
     564       
     565        irq_spinlock_unlock(&box->lock, true);
     566       
    508567        /* Free unused call */
    509568        if (call)
     
    511570}
    512571
    513 /** Cleans up all IPC communication of the current task.
     572/** Clean up all IPC communication of the current task.
    514573 *
    515574 * Note: ipc_hangup sets returning answerbox to TASK->answerbox, you
    516575 * have to change it as well if you want to cleanup other tasks than TASK.
     576 *
    517577 */
    518578void ipc_cleanup(void)
    519579{
    520         int i;
    521         call_t *call;
    522 
    523580        /* Disconnect all our phones ('ipc_phone_hangup') */
     581        size_t i;
    524582        for (i = 0; i < IPC_MAX_PHONES; i++)
    525583                ipc_phone_hangup(&TASK->phones[i]);
    526 
     584       
    527585        /* Unsubscribe from any event notifications. */
    528586        event_cleanup_answerbox(&TASK->answerbox);
    529 
     587       
    530588        /* Disconnect all connected irqs */
    531589        ipc_irq_cleanup(&TASK->answerbox);
    532 
     590       
    533591        /* Disconnect all phones connected to our regular answerbox */
    534592        ipc_answerbox_slam_phones(&TASK->answerbox, false);
    535 
     593       
    536594#ifdef CONFIG_UDEBUG
    537595        /* Clean up kbox thread and communications */
    538596        ipc_kbox_cleanup();
    539597#endif
    540 
     598       
    541599        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    542         spinlock_lock(&TASK->answerbox.lock);
     600        irq_spinlock_lock(&TASK->answerbox.lock, true);
    543601        ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
    544602        ipc_cleanup_call_list(&TASK->answerbox.calls);
    545         spinlock_unlock(&TASK->answerbox.lock);
    546        
    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 */
     603        irq_spinlock_unlock(&TASK->answerbox.lock, true);
     604       
     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                 */
    552626                for (i = 0; i < IPC_MAX_PHONES; i++) {
    553627                        if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
    554                             atomic_get(&TASK->phones[i].active_calls) == 0)
     628                            atomic_get(&TASK->phones[i].active_calls) == 0) {
    555629                                TASK->phones[i].state = IPC_PHONE_FREE;
     630                                TASK->phones[i].callee = NULL;
     631                        }
    556632                       
    557                         /* Just for sure, we might have had some
    558                          * IPC_PHONE_CONNECTING phones */
     633                        /*
     634                         * Just for sure, we might have had some
     635                         * IPC_PHONE_CONNECTING phones
     636                         */
    559637                        if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
    560638                                ipc_phone_hangup(&TASK->phones[i]);
    561                         /* If the hangup succeeded, it has sent a HANGUP
     639                       
     640                        /*
     641                         * If the hangup succeeded, it has sent a HANGUP
    562642                         * message, the IPC is now in HUNGUP state, we
    563                          * wait for the reply to come */
     643                         * wait for the reply to come
     644                         */
    564645                       
    565646                        if (TASK->phones[i].state != IPC_PHONE_FREE)
    566647                                break;
    567648                }
    568                 /* Voila, got into cleanup */
     649               
     650                /* Got into cleanup */
    569651                if (i == IPC_MAX_PHONES)
    570652                        break;
    571653               
    572                 call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
     654                call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    573655                    SYNCH_FLAGS_NONE);
    574656                ASSERT((call->flags & IPC_CALL_ANSWERED) ||
    575657                    (call->flags & IPC_CALL_NOTIF));
    576                 ASSERT(!(call->flags & IPC_CALL_STATIC_ALLOC));
    577                
    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);
     658               
    585659                ipc_call_free(call);
    586660        }
    587661}
    588662
    589 
    590 /** Initilize IPC subsystem */
     663/** Initilize IPC subsystem
     664 *
     665 */
    591666void ipc_init(void)
    592667{
    593668        ipc_call_slab = slab_cache_create("ipc_call", sizeof(call_t), 0, NULL,
    594669            NULL, 0);
    595 }
    596 
     670        ipc_answerbox_slab = slab_cache_create("ipc_answerbox",
     671            sizeof(answerbox_t), 0, NULL, NULL, 0);
     672}
    597673
    598674/** List answerbox contents.
    599675 *
    600  * @param taskid        Task ID.
     676 * @param taskid Task ID.
     677 *
    601678 */
    602679void ipc_print_task(task_id_t taskid)
    603680{
    604         task_t *task;
    605         int i;
    606         call_t *call;
    607         link_t *tmp;
    608        
    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)
     681        irq_spinlock_lock(&tasks_lock, true);
     682        task_t *task = task_find_by_id(taskid);
     683       
     684        if (!task) {
     685                irq_spinlock_unlock(&tasks_lock, true);
    615686                return;
    616 
    617         /* Print opened phones & details */
    618         printf("PHONE:\n");
     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;
    619695        for (i = 0; i < IPC_MAX_PHONES; i++) {
    620696                if (SYNCH_FAILED(mutex_trylock(&task->phones[i].lock))) {
    621                         printf("%d: mutex busy\n", i);
     697                        printf("%-10zu (mutex busy)\n", i);
    622698                        continue;
    623699                }
     700               
    624701                if (task->phones[i].state != IPC_PHONE_FREE) {
    625                         printf("%d: ", i);
     702                        printf("%-10zu %7" PRIun " ", i,
     703                            atomic_get(&task->phones[i].active_calls));
     704                       
    626705                        switch (task->phones[i].state) {
    627706                        case IPC_PHONE_CONNECTING:
    628                                 printf("connecting ");
     707                                printf("connecting");
    629708                                break;
    630709                        case IPC_PHONE_CONNECTED:
    631                                 printf("connected to: %p ",
    632                                        task->phones[i].callee);
     710                                printf("connected to %" PRIu64 " (%s)",
     711                                    task->phones[i].callee->task->taskid,
     712                                    task->phones[i].callee->task->name);
    633713                                break;
    634714                        case IPC_PHONE_SLAMMED:
    635                                 printf("slammed by: %p ",
    636                                        task->phones[i].callee);
     715                                printf("slammed by %p",
     716                                    task->phones[i].callee);
    637717                                break;
    638718                        case IPC_PHONE_HUNGUP:
    639                                 printf("hung up - was: %p ",
    640                                        task->phones[i].callee);
     719                                printf("hung up by %p",
     720                                    task->phones[i].callee);
    641721                                break;
    642722                        default:
    643723                                break;
    644724                        }
    645                         printf("active: %ld\n",
    646                             atomic_get(&task->phones[i].active_calls));
     725                       
     726                        printf("\n");
    647727                }
     728               
    648729                mutex_unlock(&task->phones[i].lock);
    649730        }
    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),
     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),
    663762                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    664763                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(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),
     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),
    678784                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    679785                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(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),
     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),
    691806                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    692807                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    693                     call->flags);
    694         }
    695 
    696         spinlock_unlock(&task->answerbox.lock);
    697         spinlock_unlock(&task->lock);
     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);
    698813}
    699814
Note: See TracChangeset for help on using the changeset viewer.