Rev 1414 | Rev 1502 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 1414 | Rev 1460 | ||
|---|---|---|---|
| Line 27... | Line 27... | ||
| 27 | */ |
27 | */ |
| 28 | 28 | ||
| 29 | /** |
29 | /** |
| 30 | * @file futex.c |
30 | * @file futex.c |
| 31 | * @brief Kernel backend for futexes. |
31 | * @brief Kernel backend for futexes. |
| 32 | * |
- | |
| 33 | * @todo Deallocation of orphaned kernel-side futex structures is not currently implemented. |
- | |
| 34 | */ |
32 | */ |
| 35 | 33 | ||
| 36 | #include <synch/futex.h> |
34 | #include <synch/futex.h> |
| 37 | #include <synch/rwlock.h> |
35 | #include <synch/rwlock.h> |
| 38 | #include <synch/spinlock.h> |
36 | #include <synch/spinlock.h> |
| 39 | #include <synch/synch.h> |
37 | #include <synch/synch.h> |
| 40 | #include <mm/frame.h> |
38 | #include <mm/frame.h> |
| 41 | #include <mm/page.h> |
39 | #include <mm/page.h> |
| 42 | #include <mm/slab.h> |
40 | #include <mm/slab.h> |
| 43 | #include <proc/thread.h> |
41 | #include <proc/thread.h> |
| - | 42 | #include <proc/task.h> |
|
| 44 | #include <genarch/mm/page_pt.h> |
43 | #include <genarch/mm/page_pt.h> |
| 45 | #include <genarch/mm/page_ht.h> |
44 | #include <genarch/mm/page_ht.h> |
| 46 | #include <adt/hash_table.h> |
45 | #include <adt/hash_table.h> |
| 47 | #include <adt/list.h> |
46 | #include <adt/list.h> |
| 48 | #include <arch.h> |
47 | #include <arch.h> |
| Line 58... | Line 57... | ||
| 58 | static futex_t *futex_find(__address paddr); |
57 | static futex_t *futex_find(__address paddr); |
| 59 | static index_t futex_ht_hash(__native *key); |
58 | static index_t futex_ht_hash(__native *key); |
| 60 | static bool futex_ht_compare(__native *key, count_t keys, link_t *item); |
59 | static bool futex_ht_compare(__native *key, count_t keys, link_t *item); |
| 61 | static void futex_ht_remove_callback(link_t *item); |
60 | static void futex_ht_remove_callback(link_t *item); |
| 62 | 61 | ||
| - | 62 | /** |
|
| 63 | /** Read-write lock protecting global futex hash table. */ |
63 | * Read-write lock protecting global futex hash table. |
| - | 64 | * It is also used to serialize access to all futex_t structures. |
|
| - | 65 | * Must be acquired before the task futex B+tree lock. |
|
| - | 66 | */ |
|
| 64 | static rwlock_t futex_ht_lock; |
67 | static rwlock_t futex_ht_lock; |
| 65 | 68 | ||
| 66 | /** Futex hash table. */ |
69 | /** Futex hash table. */ |
| 67 | static hash_table_t futex_ht; |
70 | static hash_table_t futex_ht; |
| 68 | 71 | ||
| Line 87... | Line 90... | ||
| 87 | void futex_initialize(futex_t *futex) |
90 | void futex_initialize(futex_t *futex) |
| 88 | { |
91 | { |
| 89 | waitq_initialize(&futex->wq); |
92 | waitq_initialize(&futex->wq); |
| 90 | link_initialize(&futex->ht_link); |
93 | link_initialize(&futex->ht_link); |
| 91 | futex->paddr = 0; |
94 | futex->paddr = 0; |
| - | 95 | futex->refcount = 1; |
|
| 92 | } |
96 | } |
| 93 | 97 | ||
| 94 | /** Sleep in futex wait queue. |
98 | /** Sleep in futex wait queue. |
| 95 | * |
99 | * |
| 96 | * @param uaddr Userspace address of the futex counter. |
100 | * @param uaddr Userspace address of the futex counter. |
| Line 166... | Line 170... | ||
| 166 | return 0; |
170 | return 0; |
| 167 | } |
171 | } |
| 168 | 172 | ||
| 169 | /** Find kernel address of the futex structure corresponding to paddr. |
173 | /** Find kernel address of the futex structure corresponding to paddr. |
| 170 | * |
174 | * |
| 171 | * If the structure does not exist alreay, a new one is created. |
175 | * If the structure does not exist already, a new one is created. |
| 172 | * |
176 | * |
| 173 | * @param paddr Physical address of the userspace futex counter. |
177 | * @param paddr Physical address of the userspace futex counter. |
| 174 | * |
178 | * |
| 175 | * @return Address of the kernel futex structure. |
179 | * @return Address of the kernel futex structure. |
| 176 | */ |
180 | */ |
| 177 | futex_t *futex_find(__address paddr) |
181 | futex_t *futex_find(__address paddr) |
| 178 | { |
182 | { |
| 179 | link_t *item; |
183 | link_t *item; |
| 180 | futex_t *futex; |
184 | futex_t *futex; |
| - | 185 | btree_node_t *leaf; |
|
| 181 | 186 | ||
| 182 | /* |
187 | /* |
| 183 | * Find the respective futex structure |
188 | * Find the respective futex structure |
| 184 | * or allocate new one if it does not exist already. |
189 | * or allocate new one if it does not exist already. |
| 185 | */ |
190 | */ |
| 186 | rwlock_read_lock(&futex_ht_lock); |
191 | rwlock_read_lock(&futex_ht_lock); |
| 187 | item = hash_table_find(&futex_ht, &paddr); |
192 | item = hash_table_find(&futex_ht, &paddr); |
| 188 | if (item) { |
193 | if (item) { |
| 189 | futex = hash_table_get_instance(item, futex_t, ht_link); |
194 | futex = hash_table_get_instance(item, futex_t, ht_link); |
| - | 195 | ||
| - | 196 | /* |
|
| - | 197 | * See if the current task knows this futex. |
|
| - | 198 | */ |
|
| - | 199 | mutex_lock(&TASK->futexes_lock); |
|
| - | 200 | if (!btree_search(&TASK->futexes, paddr, &leaf)) { |
|
| - | 201 | /* |
|
| - | 202 | * The futex is new to the current task. |
|
| - | 203 | * However, we only have read access. |
|
| - | 204 | * Gain write access and try again. |
|
| - | 205 | */ |
|
| - | 206 | mutex_unlock(&TASK->futexes_lock); |
|
| - | 207 | goto gain_write_access; |
|
| - | 208 | } |
|
| - | 209 | mutex_unlock(&TASK->futexes_lock); |
|
| - | 210 | ||
| 190 | rwlock_read_unlock(&futex_ht_lock); |
211 | rwlock_read_unlock(&futex_ht_lock); |
| 191 | } else { |
212 | } else { |
| - | 213 | gain_write_access: |
|
| 192 | /* |
214 | /* |
| 193 | * Upgrade to writer is not currently supported, |
215 | * Upgrade to writer is not currently supported, |
| 194 | * therefore, it is necessary to release the read lock |
216 | * therefore, it is necessary to release the read lock |
| 195 | * and reacquire it as a writer. |
217 | * and reacquire it as a writer. |
| 196 | */ |
218 | */ |
| Line 202... | Line 224... | ||
| 202 | * the hash table once again with write access. |
224 | * the hash table once again with write access. |
| 203 | */ |
225 | */ |
| 204 | item = hash_table_find(&futex_ht, &paddr); |
226 | item = hash_table_find(&futex_ht, &paddr); |
| 205 | if (item) { |
227 | if (item) { |
| 206 | futex = hash_table_get_instance(item, futex_t, ht_link); |
228 | futex = hash_table_get_instance(item, futex_t, ht_link); |
| - | 229 | ||
| - | 230 | /* |
|
| - | 231 | * See if this futex is known to the current task. |
|
| - | 232 | */ |
|
| - | 233 | mutex_lock(&TASK->futexes_lock); |
|
| - | 234 | if (!btree_search(&TASK->futexes, paddr, &leaf)) { |
|
| - | 235 | /* |
|
| - | 236 | * The futex is new to the current task. |
|
| - | 237 | * Upgrade its reference count and put it to the |
|
| - | 238 | * current task's B+tree of known futexes. |
|
| - | 239 | */ |
|
| - | 240 | futex->refcount++; |
|
| - | 241 | btree_insert(&TASK->futexes, paddr, futex, leaf); |
|
| - | 242 | } |
|
| - | 243 | mutex_unlock(&TASK->futexes_lock); |
|
| - | 244 | ||
| 207 | rwlock_write_unlock(&futex_ht_lock); |
245 | rwlock_write_unlock(&futex_ht_lock); |
| 208 | } else { |
246 | } else { |
| 209 | futex = (futex_t *) malloc(sizeof(futex_t), 0); |
247 | futex = (futex_t *) malloc(sizeof(futex_t), 0); |
| 210 | futex_initialize(futex); |
248 | futex_initialize(futex); |
| 211 | futex->paddr = paddr; |
249 | futex->paddr = paddr; |
| 212 | hash_table_insert(&futex_ht, &paddr, &futex->ht_link); |
250 | hash_table_insert(&futex_ht, &paddr, &futex->ht_link); |
| - | 251 | ||
| - | 252 | /* |
|
| - | 253 | * This is the first task referencing the futex. |
|
| - | 254 | * It can be directly inserted into its |
|
| - | 255 | * B+tree of known futexes. |
|
| - | 256 | */ |
|
| - | 257 | mutex_lock(&TASK->futexes_lock); |
|
| - | 258 | btree_insert(&TASK->futexes, paddr, futex, NULL); |
|
| - | 259 | mutex_unlock(&TASK->futexes_lock); |
|
| - | 260 | ||
| 213 | rwlock_write_unlock(&futex_ht_lock); |
261 | rwlock_write_unlock(&futex_ht_lock); |
| 214 | } |
262 | } |
| 215 | } |
263 | } |
| 216 | 264 | ||
| 217 | return futex; |
265 | return futex; |