Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/futex.c

    ra49a1a1 r4774a32  
    3737
    3838#include <synch/futex.h>
    39 #include <synch/mutex.h>
     39#include <synch/rwlock.h>
    4040#include <synch/spinlock.h>
    4141#include <synch/synch.h>
     
    6565
    6666/**
    67  * Mutex protecting global futex hash table.
     67 * Read-write lock protecting global futex hash table.
    6868 * It is also used to serialize access to all futex_t structures.
    6969 * Must be acquired before the task futex B+tree lock.
    7070 */
    71 static mutex_t futex_ht_lock;
     71static rwlock_t futex_ht_lock;
    7272
    7373/** Futex hash table. */
     
    8484void futex_init(void)
    8585{
    86         mutex_initialize(&futex_ht_lock, MUTEX_PASSIVE);
     86        rwlock_initialize(&futex_ht_lock);
    8787        hash_table_create(&futex_ht, FUTEX_HT_SIZE, 1, &futex_ht_ops);
    8888}
     
    113113        uintptr_t paddr;
    114114        pte_t *t;
     115        ipl_t ipl;
    115116        int rc;
    116117       
     118        ipl = interrupts_disable();
     119
    117120        /*
    118121         * Find physical address of futex counter.
     
    122125        if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
    123126                page_table_unlock(AS, true);
     127                interrupts_restore(ipl);
    124128                return (unative_t) ENOENT;
    125129        }
     
    127131        page_table_unlock(AS, true);
    128132       
     133        interrupts_restore(ipl);       
     134
    129135        futex = futex_find(paddr);
    130136
     
    150156        uintptr_t paddr;
    151157        pte_t *t;
     158        ipl_t ipl;
     159       
     160        ipl = interrupts_disable();
    152161       
    153162        /*
     
    158167        if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
    159168                page_table_unlock(AS, true);
     169                interrupts_restore(ipl);
    160170                return (unative_t) ENOENT;
    161171        }
     
    163173        page_table_unlock(AS, true);
    164174       
     175        interrupts_restore(ipl);
     176
    165177        futex = futex_find(paddr);
    166178               
     
    188200         * or allocate new one if it does not exist already.
    189201         */
    190         mutex_lock(&futex_ht_lock);
     202        rwlock_read_lock(&futex_ht_lock);
    191203        item = hash_table_find(&futex_ht, &paddr);
    192204        if (item) {
     
    200212                        /*
    201213                         * The futex is new to the current task.
    202                          * Upgrade its reference count and put it to the
    203                          * current task's B+tree of known futexes.
     214                         * However, we only have read access.
     215                         * Gain write access and try again.
    204216                         */
    205                         futex->refcount++;
    206                         btree_insert(&TASK->futexes, paddr, futex, leaf);
     217                        mutex_unlock(&TASK->futexes_lock);
     218                        goto gain_write_access;
    207219                }
    208220                mutex_unlock(&TASK->futexes_lock);
     221
     222                rwlock_read_unlock(&futex_ht_lock);
    209223        } else {
    210                 futex = (futex_t *) malloc(sizeof(futex_t), 0);
    211                 futex_initialize(futex);
    212                 futex->paddr = paddr;
    213                 hash_table_insert(&futex_ht, &paddr, &futex->ht_link);
     224gain_write_access:
     225                /*
     226                 * Upgrade to writer is not currently supported,
     227                 * therefore, it is necessary to release the read lock
     228                 * and reacquire it as a writer.
     229                 */
     230                rwlock_read_unlock(&futex_ht_lock);
     231
     232                rwlock_write_lock(&futex_ht_lock);
     233                /*
     234                 * Avoid possible race condition by searching
     235                 * the hash table once again with write access.
     236                 */
     237                item = hash_table_find(&futex_ht, &paddr);
     238                if (item) {
     239                        futex = hash_table_get_instance(item, futex_t, ht_link);
    214240                       
    215                 /*
    216                  * This is the first task referencing the futex.
    217                  * It can be directly inserted into its
    218                  * B+tree of known futexes.
    219                  */
    220                 mutex_lock(&TASK->futexes_lock);
    221                 btree_insert(&TASK->futexes, paddr, futex, NULL);
    222                 mutex_unlock(&TASK->futexes_lock);
    223                
     241                        /*
     242                         * See if this futex is known to the current task.
     243                         */
     244                        mutex_lock(&TASK->futexes_lock);
     245                        if (!btree_search(&TASK->futexes, paddr, &leaf)) {
     246                                /*
     247                                 * The futex is new to the current task.
     248                                 * Upgrade its reference count and put it to the
     249                                 * current task's B+tree of known futexes.
     250                                 */
     251                                futex->refcount++;
     252                                btree_insert(&TASK->futexes, paddr, futex,
     253                                    leaf);
     254                        }
     255                        mutex_unlock(&TASK->futexes_lock);
     256       
     257                        rwlock_write_unlock(&futex_ht_lock);
     258                } else {
     259                        futex = (futex_t *) malloc(sizeof(futex_t), 0);
     260                        futex_initialize(futex);
     261                        futex->paddr = paddr;
     262                        hash_table_insert(&futex_ht, &paddr, &futex->ht_link);
     263                       
     264                        /*
     265                         * This is the first task referencing the futex.
     266                         * It can be directly inserted into its
     267                         * B+tree of known futexes.
     268                         */
     269                        mutex_lock(&TASK->futexes_lock);
     270                        btree_insert(&TASK->futexes, paddr, futex, NULL);
     271                        mutex_unlock(&TASK->futexes_lock);
     272                       
     273                        rwlock_write_unlock(&futex_ht_lock);
     274                }
    224275        }
    225         mutex_unlock(&futex_ht_lock);
    226276       
    227277        return futex;
     
    274324        link_t *cur;
    275325       
    276         mutex_lock(&futex_ht_lock);
     326        rwlock_write_lock(&futex_ht_lock);
    277327        mutex_lock(&TASK->futexes_lock);
    278328
     
    294344       
    295345        mutex_unlock(&TASK->futexes_lock);
    296         mutex_unlock(&futex_ht_lock);
     346        rwlock_write_unlock(&futex_ht_lock);
    297347}
    298348
Note: See TracChangeset for help on using the changeset viewer.