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; |