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