Changeset 9e87562 in mainline for kernel/generic/src/ipc/ipc.c


Ignore:
Timestamp:
2017-09-18T20:52:12Z (7 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6abfd250
Parents:
e5f5ce0
Message:

Make all accesses to capabilites exclusive

This commit makes sure that all accesses to the capabilities array and other
metadata are protected by a mutex. This is necessary for future resizing of the
capabilities array.

Group task's capabilities by type so that it is possible to visit all
capabilities of the given type effectively.

Provide cap_publish() and cap_unpublish() to automate steps that make the
capability visible/invisible to userspace and insert/remove the capability from
the respective type list.

File:
1 edited

Legend:

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

    re5f5ce0 r9e87562  
    710710                 * Nota bene: there may still be answers waiting for pick up.
    711711                 */
    712                 spinlock_unlock(&TASK->active_calls_lock);     
     712                spinlock_unlock(&TASK->active_calls_lock);
    713713                return;
    714714        }
     
    723723                 * call on the list.
    724724                 */
    725                 spinlock_unlock(&TASK->active_calls_lock);     
     725                spinlock_unlock(&TASK->active_calls_lock);
    726726                goto restart;
    727727        }
     
    730730
    731731        goto restart;
     732}
     733
     734static bool phone_cap_wait_cb(cap_t *cap, void *arg)
     735{
     736        phone_t *phone = (phone_t *) cap->kobject;
     737        bool *restart = (bool *) arg;
     738
     739        mutex_lock(&phone->lock);
     740        if ((phone->state == IPC_PHONE_HUNGUP) &&
     741            (atomic_get(&phone->active_calls) == 0)) {
     742                phone->state = IPC_PHONE_FREE;
     743                phone->callee = NULL;
     744        }
     745
     746        /*
     747         * We might have had some IPC_PHONE_CONNECTING phones at the beginning
     748         * of ipc_cleanup(). Depending on whether these were forgotten or
     749         * answered, they will eventually enter the IPC_PHONE_FREE or
     750         * IPC_PHONE_CONNECTED states, respectively.  In the latter case, the
     751         * other side may slam the open phones at any time, in which case we
     752         * will get an IPC_PHONE_SLAMMED phone.
     753         */
     754        if ((phone->state == IPC_PHONE_CONNECTED) ||
     755            (phone->state == IPC_PHONE_SLAMMED)) {
     756                mutex_unlock(&phone->lock);
     757                ipc_phone_hangup(phone);
     758                /*
     759                 * Now there may be one extra active call, which needs to be
     760                 * forgotten.
     761                 */
     762                ipc_forget_all_active_calls();
     763                *restart = true;
     764                return false;
     765        }
     766
     767        /*
     768         * If the hangup succeeded, it has sent a HANGUP message, the IPC is now
     769         * in HUNGUP state, we wait for the reply to come
     770         */
     771        if (phone->state != IPC_PHONE_FREE) {
     772                mutex_unlock(&phone->lock);
     773                return false;
     774        }
     775
     776        mutex_unlock(&phone->lock);
     777        return true;
    732778}
    733779
     
    736782{
    737783        call_t *call;
    738         bool all_clean;
     784        bool restart;
    739785
    740786restart:
     
    743789         * Locking is needed as there may be connection handshakes in progress.
    744790         */
    745         all_clean = true;
    746         for_each_cap_current(cap, CAP_TYPE_PHONE) {
    747                 phone_t *phone = (phone_t *) cap->kobject;
    748 
    749                 mutex_lock(&phone->lock);
    750                 if ((phone->state == IPC_PHONE_HUNGUP) &&
    751                     (atomic_get(&phone->active_calls) == 0)) {
    752                         phone->state = IPC_PHONE_FREE;
    753                         phone->callee = NULL;
    754                 }
    755 
    756                 /*
    757                  * We might have had some IPC_PHONE_CONNECTING phones at the
    758                  * beginning of ipc_cleanup(). Depending on whether these were
    759                  * forgotten or answered, they will eventually enter the
    760                  * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
    761                  * In the latter case, the other side may slam the open phones
    762                  * at any time, in which case we will get an IPC_PHONE_SLAMMED
    763                  * phone.
    764                  */
    765                 if ((phone->state == IPC_PHONE_CONNECTED) ||
    766                     (phone->state == IPC_PHONE_SLAMMED)) {
    767                         mutex_unlock(&phone->lock);
    768                         ipc_phone_hangup(phone);
    769                         /*
    770                          * Now there may be one extra active call, which needs
    771                          * to be forgotten.
    772                          */
    773                         ipc_forget_all_active_calls();
    774                         goto restart;
    775                 }
    776 
    777                 /*
    778                  * If the hangup succeeded, it has sent a HANGUP message, the
    779                  * IPC is now in HUNGUP state, we wait for the reply to come
    780                  */
    781                 if (phone->state != IPC_PHONE_FREE) {
    782                         mutex_unlock(&phone->lock);
    783                         all_clean = false;
    784                         break;
    785                 }
    786 
    787                 mutex_unlock(&phone->lock);
    788         }
    789                
    790         /* Got into cleanup */
    791         if (all_clean)
     791        restart = false;
     792        if (caps_apply_to_all(TASK, CAP_TYPE_PHONE, phone_cap_wait_cb,
     793            &restart)) {
     794                /* Got into cleanup */
    792795                return;
    793                
     796        }
     797        if (restart)
     798                goto restart;
     799       
    794800        call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    795801            SYNCH_FLAGS_NONE);
     
    800806        ipc_call_free(call);
    801807        goto restart;
     808}
     809
     810static bool phone_cap_cleanup_cb(cap_t *cap, void *arg)
     811{
     812        phone_t *phone = (phone_t *) cap->kobject;
     813        ipc_phone_hangup(phone);
     814        return true;
     815}
     816
     817static bool irq_cap_cleanup_cb(cap_t *cap, void *arg)
     818{
     819        ipc_irq_unsubscribe(&TASK->answerbox, cap->handle);
     820        return true;
    802821}
    803822
     
    821840
    822841        /* Disconnect all our phones ('ipc_phone_hangup') */
    823         for_each_cap_current(cap, CAP_TYPE_PHONE) {
    824                 phone_t *phone = (phone_t *) cap->kobject;
    825                 ipc_phone_hangup(phone);
    826         }
     842        caps_apply_to_all(TASK, CAP_TYPE_PHONE, phone_cap_cleanup_cb, NULL);
    827843       
    828844        /* Unsubscribe from any event notifications. */
     
    830846       
    831847        /* Disconnect all connected IRQs */
    832         for_each_cap_current(cap, CAP_TYPE_IRQ) {
    833                 ipc_irq_unsubscribe(&TASK->answerbox, cap->handle);
    834         }
     848        caps_apply_to_all(TASK, CAP_TYPE_IRQ, irq_cap_cleanup_cb, NULL);
    835849       
    836850        /* Disconnect all phones connected to our regular answerbox */
     
    896910}
    897911
     912static bool print_task_phone_cb(cap_t *cap, void *arg)
     913{
     914        phone_t *phone = (phone_t *) cap->kobject;
     915
     916        mutex_lock(&phone->lock);
     917        if (phone->state != IPC_PHONE_FREE) {
     918                printf("%-11d %7" PRIun " ", cap->handle,
     919                    atomic_get(&phone->active_calls));
     920               
     921                switch (phone->state) {
     922                case IPC_PHONE_CONNECTING:
     923                        printf("connecting");
     924                        break;
     925                case IPC_PHONE_CONNECTED:
     926                        printf("connected to %" PRIu64 " (%s)",
     927                            phone->callee->task->taskid,
     928                            phone->callee->task->name);
     929                        break;
     930                case IPC_PHONE_SLAMMED:
     931                        printf("slammed by %p", phone->callee);
     932                        break;
     933                case IPC_PHONE_HUNGUP:
     934                        printf("hung up by %p", phone->callee);
     935                        break;
     936                default:
     937                        break;
     938                }
     939               
     940                printf("\n");
     941        }
     942        mutex_unlock(&phone->lock);
     943
     944        return true;
     945}
     946
    898947/** List answerbox contents.
    899948 *
     
    905954        irq_spinlock_lock(&tasks_lock, true);
    906955        task_t *task = task_find_by_id(taskid);
    907        
    908956        if (!task) {
    909957                irq_spinlock_unlock(&tasks_lock, true);
    910958                return;
    911959        }
    912        
    913         /* Hand-over-hand locking */
    914         irq_spinlock_exchange(&tasks_lock, &task->lock);
     960        task_hold(task);
     961        irq_spinlock_unlock(&tasks_lock, true);
    915962       
    916963        printf("[phone cap] [calls] [state\n");
    917964       
    918         for_each_cap(task, cap, CAP_TYPE_PHONE) {
    919                 phone_t *phone = (phone_t *) cap->kobject;
    920        
    921                 if (SYNCH_FAILED(mutex_trylock(&phone->lock))) {
    922                         printf("%-11d (mutex busy)\n", cap->handle);
    923                         continue;
    924                 }
    925                
    926                 if (phone->state != IPC_PHONE_FREE) {
    927                         printf("%-11d %7" PRIun " ", cap->handle,
    928                             atomic_get(&phone->active_calls));
    929                        
    930                         switch (phone->state) {
    931                         case IPC_PHONE_CONNECTING:
    932                                 printf("connecting");
    933                                 break;
    934                         case IPC_PHONE_CONNECTED:
    935                                 printf("connected to %" PRIu64 " (%s)",
    936                                     phone->callee->task->taskid,
    937                                     phone->callee->task->name);
    938                                 break;
    939                         case IPC_PHONE_SLAMMED:
    940                                 printf("slammed by %p", phone->callee);
    941                                 break;
    942                         case IPC_PHONE_HUNGUP:
    943                                 printf("hung up by %p", phone->callee);
    944                                 break;
    945                         default:
    946                                 break;
    947                         }
    948                        
    949                         printf("\n");
    950                 }
    951                
    952                 mutex_unlock(&phone->lock);
    953         }
    954        
     965        caps_apply_to_all(task, CAP_TYPE_PHONE, print_task_phone_cb, NULL);
     966       
     967        irq_spinlock_lock(&task->lock, true);
    955968        irq_spinlock_lock(&task->answerbox.lock, false);
    956969       
     
    974987        irq_spinlock_unlock(&task->answerbox.lock, false);
    975988        irq_spinlock_unlock(&task->lock, true);
     989
     990        task_release(task);
    976991}
    977992
Note: See TracChangeset for help on using the changeset viewer.