Changeset 879585a3 in mainline for kernel/generic/src/mm/as.c


Ignore:
Timestamp:
2007-03-31T22:22:50Z (17 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
31d8e10
Parents:
563c2dd
Message:

Simplify synchronization in as_switch().
The function was oversynchronized, which
was causing deadlocks on the address
space mutex.

Now, address spaces can only be switched
when the asidlock is held. This also protects
stealing of ASIDs. No other synchronization
is necessary.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/as.c

    r563c2dd r879585a3  
    9696
    9797/**
    98  * This lock protects inactive_as_with_asid_head list. It must be acquired
    99  * before as_t mutex.
    100  */
    101 SPINLOCK_INITIALIZE(inactive_as_with_asid_lock);
     98 * This lock serializes access to the ASID subsystem.
     99 * It protects:
     100 * - inactive_as_with_asid_head list
     101 * - as->asid for each as of the as_t type
     102 * - asids_allocated counter
     103 */
     104SPINLOCK_INITIALIZE(asidlock);
    102105
    103106/**
     
    206209         * it is safe not to lock its mutex.
    207210         */
     211
    208212        ipl = interrupts_disable();
    209         spinlock_lock(&inactive_as_with_asid_lock);
     213        spinlock_lock(&asidlock);
    210214        if (as->asid != ASID_INVALID && as != AS_KERNEL) {
    211215                if (as != AS && as->cpu_refcount == 0)
     
    213217                asid_put(as->asid);
    214218        }
    215         spinlock_unlock(&inactive_as_with_asid_lock);
     219        spinlock_unlock(&asidlock);
    216220
    217221        /*
     
    861865 *
    862866 * Note that this function cannot sleep as it is essentially a part of
    863  * scheduling. Sleeping here would lead to deadlock on wakeup.
     867 * scheduling. Sleeping here would lead to deadlock on wakeup. Another
     868 * thing which is forbidden in this context is locking the address space.
    864869 *
    865870 * @param old Old address space or NULL.
     
    868873void as_switch(as_t *old_as, as_t *new_as)
    869874{
    870         ipl_t ipl;
    871         bool needs_asid = false;
    872        
    873         ipl = interrupts_disable();
    874         spinlock_lock(&inactive_as_with_asid_lock);
     875        spinlock_lock(&asidlock);
    875876
    876877        /*
     
    878879         */     
    879880        if (old_as) {
    880                 mutex_lock_active(&old_as->lock);
    881881                ASSERT(old_as->cpu_refcount);
    882882                if((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
     
    891891                            &inactive_as_with_asid_head);
    892892                }
    893                 mutex_unlock(&old_as->lock);
    894893
    895894                /*
     
    903902         * Second, prepare the new address space.
    904903         */
    905         mutex_lock_active(&new_as->lock);
    906904        if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) {
    907                 if (new_as->asid != ASID_INVALID) {
     905                if (new_as->asid != ASID_INVALID)
    908906                        list_remove(&new_as->inactive_as_with_asid_link);
    909                 } else {
    910                         /*
    911                          * Defer call to asid_get() until new_as->lock is released.
    912                          */
    913                         needs_asid = true;
    914                 }
     907                else
     908                        new_as->asid = asid_get();
    915909        }
    916910#ifdef AS_PAGE_TABLE
    917911        SET_PTL0_ADDRESS(new_as->genarch.page_table);
    918912#endif
    919         mutex_unlock(&new_as->lock);
    920 
    921         if (needs_asid) {
    922                 /*
    923                  * Allocation of new ASID was deferred
    924                  * until now in order to avoid deadlock.
    925                  */
    926                 asid_t asid;
    927                
    928                 asid = asid_get();
    929                 mutex_lock_active(&new_as->lock);
    930                 new_as->asid = asid;
    931                 mutex_unlock(&new_as->lock);
    932         }
    933         spinlock_unlock(&inactive_as_with_asid_lock);
    934         interrupts_restore(ipl);
    935913       
    936914        /*
     
    939917         */
    940918        as_install_arch(new_as);
     919
     920        spinlock_unlock(&asidlock);
    941921       
    942922        AS = new_as;
Note: See TracChangeset for help on using the changeset viewer.