Ignore:
File:
1 edited

Legend:

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

    r96b02eb9 r98000fb  
    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>
     
    6060
    6161static futex_t *futex_find(uintptr_t paddr);
    62 static size_t futex_ht_hash(sysarg_t *key);
    63 static bool futex_ht_compare(sysarg_t *key, size_t keys, link_t *item);
     62static size_t futex_ht_hash(unative_t *key);
     63static bool futex_ht_compare(unative_t *key, size_t keys, link_t *item);
    6464static void futex_ht_remove_callback(link_t *item);
    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}
     
    9090/** Initialize kernel futex structure.
    9191 *
    92  * @param futex         Kernel futex structure.
     92 * @param futex Kernel futex structure.
    9393 */
    9494void futex_initialize(futex_t *futex)
     
    102102/** Sleep in futex wait queue.
    103103 *
    104  * @param uaddr         Userspace address of the futex counter.
    105  *
    106  * @return              If there is no physical mapping for uaddr ENOENT is
    107  *                      returned. Otherwise returns a wait result as defined in
    108  *                      synch.h.
    109  */
    110 sysarg_t sys_futex_sleep(uintptr_t uaddr)
     104 * @param uaddr Userspace address of the futex counter.
     105 * @param usec If non-zero, number of microseconds this thread is willing to
     106 *     sleep.
     107 * @param flags Select mode of operation.
     108 *
     109 * @return One of ESYNCH_TIMEOUT, ESYNCH_OK_ATOMIC and ESYNCH_OK_BLOCKED. See
     110 *     synch.h. If there is no physical mapping for uaddr ENOENT is returned.
     111 */
     112unative_t sys_futex_sleep_timeout(uintptr_t uaddr, uint32_t usec, int flags)
    111113{
    112114        futex_t *futex;
    113115        uintptr_t paddr;
    114116        pte_t *t;
     117        ipl_t ipl;
    115118        int rc;
    116119       
     120        ipl = interrupts_disable();
     121
    117122        /*
    118123         * Find physical address of futex counter.
     
    122127        if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
    123128                page_table_unlock(AS, true);
    124                 return (sysarg_t) ENOENT;
     129                interrupts_restore(ipl);
     130                return (unative_t) ENOENT;
    125131        }
    126132        paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
    127133        page_table_unlock(AS, true);
    128134       
     135        interrupts_restore(ipl);       
     136
    129137        futex = futex_find(paddr);
    130138
     
    132140        udebug_stoppable_begin();
    133141#endif
    134         rc = waitq_sleep_timeout(&futex->wq, 0, SYNCH_FLAGS_INTERRUPTIBLE);
     142        rc = waitq_sleep_timeout(&futex->wq, usec, flags |
     143            SYNCH_FLAGS_INTERRUPTIBLE);
     144
    135145#ifdef CONFIG_UDEBUG
    136146        udebug_stoppable_end();
    137147#endif
    138         return (sysarg_t) rc;
     148        return (unative_t) rc;
    139149}
    140150
    141151/** Wakeup one thread waiting in futex wait queue.
    142152 *
    143  * @param uaddr         Userspace address of the futex counter.
    144  *
    145  * @return              ENOENT if there is no physical mapping for uaddr.
    146  */
    147 sysarg_t sys_futex_wakeup(uintptr_t uaddr)
     153 * @param uaddr Userspace address of the futex counter.
     154 *
     155 * @return ENOENT if there is no physical mapping for uaddr.
     156 */
     157unative_t sys_futex_wakeup(uintptr_t uaddr)
    148158{
    149159        futex_t *futex;
    150160        uintptr_t paddr;
    151161        pte_t *t;
     162        ipl_t ipl;
     163       
     164        ipl = interrupts_disable();
    152165       
    153166        /*
     
    158171        if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
    159172                page_table_unlock(AS, true);
    160                 return (sysarg_t) ENOENT;
     173                interrupts_restore(ipl);
     174                return (unative_t) ENOENT;
    161175        }
    162176        paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
    163177        page_table_unlock(AS, true);
    164178       
     179        interrupts_restore(ipl);
     180
    165181        futex = futex_find(paddr);
    166182               
     
    174190 * If the structure does not exist already, a new one is created.
    175191 *
    176  * @param paddr         Physical address of the userspace futex counter.
    177  *
    178  * @return              Address of the kernel futex structure.
     192 * @param paddr Physical address of the userspace futex counter.
     193 *
     194 * @return Address of the kernel futex structure.
    179195 */
    180196futex_t *futex_find(uintptr_t paddr)
     
    188204         * or allocate new one if it does not exist already.
    189205         */
    190         mutex_lock(&futex_ht_lock);
     206        rwlock_read_lock(&futex_ht_lock);
    191207        item = hash_table_find(&futex_ht, &paddr);
    192208        if (item) {
     
    200216                        /*
    201217                         * 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.
     218                         * However, we only have read access.
     219                         * Gain write access and try again.
    204220                         */
    205                         futex->refcount++;
    206                         btree_insert(&TASK->futexes, paddr, futex, leaf);
     221                        mutex_unlock(&TASK->futexes_lock);
     222                        goto gain_write_access;
    207223                }
    208224                mutex_unlock(&TASK->futexes_lock);
     225
     226                rwlock_read_unlock(&futex_ht_lock);
    209227        } 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);
     228gain_write_access:
     229                /*
     230                 * Upgrade to writer is not currently supported,
     231                 * therefore, it is necessary to release the read lock
     232                 * and reacquire it as a writer.
     233                 */
     234                rwlock_read_unlock(&futex_ht_lock);
     235
     236                rwlock_write_lock(&futex_ht_lock);
     237                /*
     238                 * Avoid possible race condition by searching
     239                 * the hash table once again with write access.
     240                 */
     241                item = hash_table_find(&futex_ht, &paddr);
     242                if (item) {
     243                        futex = hash_table_get_instance(item, futex_t, ht_link);
    214244                       
    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                
     245                        /*
     246                         * See if this futex is known to the current task.
     247                         */
     248                        mutex_lock(&TASK->futexes_lock);
     249                        if (!btree_search(&TASK->futexes, paddr, &leaf)) {
     250                                /*
     251                                 * The futex is new to the current task.
     252                                 * Upgrade its reference count and put it to the
     253                                 * current task's B+tree of known futexes.
     254                                 */
     255                                futex->refcount++;
     256                                btree_insert(&TASK->futexes, paddr, futex,
     257                                    leaf);
     258                        }
     259                        mutex_unlock(&TASK->futexes_lock);
     260       
     261                        rwlock_write_unlock(&futex_ht_lock);
     262                } else {
     263                        futex = (futex_t *) malloc(sizeof(futex_t), 0);
     264                        futex_initialize(futex);
     265                        futex->paddr = paddr;
     266                        hash_table_insert(&futex_ht, &paddr, &futex->ht_link);
     267                       
     268                        /*
     269                         * This is the first task referencing the futex.
     270                         * It can be directly inserted into its
     271                         * B+tree of known futexes.
     272                         */
     273                        mutex_lock(&TASK->futexes_lock);
     274                        btree_insert(&TASK->futexes, paddr, futex, NULL);
     275                        mutex_unlock(&TASK->futexes_lock);
     276                       
     277                        rwlock_write_unlock(&futex_ht_lock);
     278                }
    224279        }
    225         mutex_unlock(&futex_ht_lock);
    226280       
    227281        return futex;
     
    230284/** Compute hash index into futex hash table.
    231285 *
    232  * @param key           Address where the key (i.e. physical address of futex
    233  *                      counter) is stored.
    234  *
    235  * @return              Index into futex hash table.
    236  */
    237 size_t futex_ht_hash(sysarg_t *key)
     286 * @param key Address where the key (i.e. physical address of futex counter) is
     287 *    stored.
     288 *
     289 * @return Index into futex hash table.
     290 */
     291size_t futex_ht_hash(unative_t *key)
    238292{
    239293        return (*key & (FUTEX_HT_SIZE - 1));
     
    242296/** Compare futex hash table item with a key.
    243297 *
    244  * @param key           Address where the key (i.e. physical address of futex
    245  *                      counter) is stored.
    246  *
    247  * @return              True if the item matches the key. False otherwise.
    248  */
    249 bool futex_ht_compare(sysarg_t *key, size_t keys, link_t *item)
     298 * @param key Address where the key (i.e. physical address of futex counter) is
     299 *    stored.
     300 *
     301 * @return True if the item matches the key. False otherwise.
     302 */
     303bool futex_ht_compare(unative_t *key, size_t keys, link_t *item)
    250304{
    251305        futex_t *futex;
     
    259313/** Callback for removal items from futex hash table.
    260314 *
    261  * @param item          Item removed from the hash table.
     315 * @param item Item removed from the hash table.
    262316 */
    263317void futex_ht_remove_callback(link_t *item)
     
    274328        link_t *cur;
    275329       
    276         mutex_lock(&futex_ht_lock);
     330        rwlock_write_lock(&futex_ht_lock);
    277331        mutex_lock(&TASK->futexes_lock);
    278332
     
    294348       
    295349        mutex_unlock(&TASK->futexes_lock);
    296         mutex_unlock(&futex_ht_lock);
     350        rwlock_write_unlock(&futex_ht_lock);
    297351}
    298352
Note: See TracChangeset for help on using the changeset viewer.