Changes in kernel/generic/src/synch/futex.c [96b02eb9:98000fb] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/synch/futex.c
r96b02eb9 r98000fb 37 37 38 38 #include <synch/futex.h> 39 #include <synch/ mutex.h>39 #include <synch/rwlock.h> 40 40 #include <synch/spinlock.h> 41 41 #include <synch/synch.h> … … 60 60 61 61 static 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);62 static size_t futex_ht_hash(unative_t *key); 63 static bool futex_ht_compare(unative_t *key, size_t keys, link_t *item); 64 64 static void futex_ht_remove_callback(link_t *item); 65 65 66 66 /** 67 * Mutexprotecting global futex hash table.67 * Read-write lock protecting global futex hash table. 68 68 * It is also used to serialize access to all futex_t structures. 69 69 * Must be acquired before the task futex B+tree lock. 70 70 */ 71 static mutex_t futex_ht_lock;71 static rwlock_t futex_ht_lock; 72 72 73 73 /** Futex hash table. */ … … 84 84 void futex_init(void) 85 85 { 86 mutex_initialize(&futex_ht_lock, MUTEX_PASSIVE);86 rwlock_initialize(&futex_ht_lock); 87 87 hash_table_create(&futex_ht, FUTEX_HT_SIZE, 1, &futex_ht_ops); 88 88 } … … 90 90 /** Initialize kernel futex structure. 91 91 * 92 * @param futex 92 * @param futex Kernel futex structure. 93 93 */ 94 94 void futex_initialize(futex_t *futex) … … 102 102 /** Sleep in futex wait queue. 103 103 * 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 */ 112 unative_t sys_futex_sleep_timeout(uintptr_t uaddr, uint32_t usec, int flags) 111 113 { 112 114 futex_t *futex; 113 115 uintptr_t paddr; 114 116 pte_t *t; 117 ipl_t ipl; 115 118 int rc; 116 119 120 ipl = interrupts_disable(); 121 117 122 /* 118 123 * Find physical address of futex counter. … … 122 127 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) { 123 128 page_table_unlock(AS, true); 124 return (sysarg_t) ENOENT; 129 interrupts_restore(ipl); 130 return (unative_t) ENOENT; 125 131 } 126 132 paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE)); 127 133 page_table_unlock(AS, true); 128 134 135 interrupts_restore(ipl); 136 129 137 futex = futex_find(paddr); 130 138 … … 132 140 udebug_stoppable_begin(); 133 141 #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 135 145 #ifdef CONFIG_UDEBUG 136 146 udebug_stoppable_end(); 137 147 #endif 138 return ( sysarg_t) rc;148 return (unative_t) rc; 139 149 } 140 150 141 151 /** Wakeup one thread waiting in futex wait queue. 142 152 * 143 * @param uaddr 144 * 145 * @return 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 */ 157 unative_t sys_futex_wakeup(uintptr_t uaddr) 148 158 { 149 159 futex_t *futex; 150 160 uintptr_t paddr; 151 161 pte_t *t; 162 ipl_t ipl; 163 164 ipl = interrupts_disable(); 152 165 153 166 /* … … 158 171 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) { 159 172 page_table_unlock(AS, true); 160 return (sysarg_t) ENOENT; 173 interrupts_restore(ipl); 174 return (unative_t) ENOENT; 161 175 } 162 176 paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE)); 163 177 page_table_unlock(AS, true); 164 178 179 interrupts_restore(ipl); 180 165 181 futex = futex_find(paddr); 166 182 … … 174 190 * If the structure does not exist already, a new one is created. 175 191 * 176 * @param paddr 177 * 178 * @return 192 * @param paddr Physical address of the userspace futex counter. 193 * 194 * @return Address of the kernel futex structure. 179 195 */ 180 196 futex_t *futex_find(uintptr_t paddr) … … 188 204 * or allocate new one if it does not exist already. 189 205 */ 190 mutex_lock(&futex_ht_lock);206 rwlock_read_lock(&futex_ht_lock); 191 207 item = hash_table_find(&futex_ht, &paddr); 192 208 if (item) { … … 200 216 /* 201 217 * The futex is new to the current task. 202 * Upgrade its reference count and put it to the203 * current task's B+tree of known futexes.218 * However, we only have read access. 219 * Gain write access and try again. 204 220 */ 205 futex->refcount++;206 btree_insert(&TASK->futexes, paddr, futex, leaf);221 mutex_unlock(&TASK->futexes_lock); 222 goto gain_write_access; 207 223 } 208 224 mutex_unlock(&TASK->futexes_lock); 225 226 rwlock_read_unlock(&futex_ht_lock); 209 227 } 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); 228 gain_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); 214 244 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 } 224 279 } 225 mutex_unlock(&futex_ht_lock);226 280 227 281 return futex; … … 230 284 /** Compute hash index into futex hash table. 231 285 * 232 * @param key Address where the key (i.e. physical address of futex233 * counter) isstored.234 * 235 * @return 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 */ 291 size_t futex_ht_hash(unative_t *key) 238 292 { 239 293 return (*key & (FUTEX_HT_SIZE - 1)); … … 242 296 /** Compare futex hash table item with a key. 243 297 * 244 * @param key Address where the key (i.e. physical address of futex245 * counter) isstored.246 * 247 * @return 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 */ 303 bool futex_ht_compare(unative_t *key, size_t keys, link_t *item) 250 304 { 251 305 futex_t *futex; … … 259 313 /** Callback for removal items from futex hash table. 260 314 * 261 * @param item 315 * @param item Item removed from the hash table. 262 316 */ 263 317 void futex_ht_remove_callback(link_t *item) … … 274 328 link_t *cur; 275 329 276 mutex_lock(&futex_ht_lock);330 rwlock_write_lock(&futex_ht_lock); 277 331 mutex_lock(&TASK->futexes_lock); 278 332 … … 294 348 295 349 mutex_unlock(&TASK->futexes_lock); 296 mutex_unlock(&futex_ht_lock);350 rwlock_write_unlock(&futex_ht_lock); 297 351 } 298 352
Note:
See TracChangeset
for help on using the changeset viewer.