00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038 #include <synch/futex.h>
00039 #include <synch/rwlock.h>
00040 #include <synch/spinlock.h>
00041 #include <synch/synch.h>
00042 #include <mm/frame.h>
00043 #include <mm/page.h>
00044 #include <mm/slab.h>
00045 #include <proc/thread.h>
00046 #include <proc/task.h>
00047 #include <genarch/mm/page_pt.h>
00048 #include <genarch/mm/page_ht.h>
00049 #include <adt/hash_table.h>
00050 #include <adt/list.h>
00051 #include <arch.h>
00052 #include <align.h>
00053 #include <panic.h>
00054 #include <errno.h>
00055 #include <print.h>
00056
00057 #define FUTEX_HT_SIZE 1024
00058
00059 static void futex_initialize(futex_t *futex);
00060
00061 static futex_t *futex_find(__address paddr);
00062 static index_t futex_ht_hash(__native *key);
00063 static bool futex_ht_compare(__native *key, count_t keys, link_t *item);
00064 static void futex_ht_remove_callback(link_t *item);
00065
00071 static rwlock_t futex_ht_lock;
00072
00074 static hash_table_t futex_ht;
00075
00077 static hash_table_operations_t futex_ht_ops = {
00078 .hash = futex_ht_hash,
00079 .compare = futex_ht_compare,
00080 .remove_callback = futex_ht_remove_callback
00081 };
00082
00084 void futex_init(void)
00085 {
00086 rwlock_initialize(&futex_ht_lock);
00087 hash_table_create(&futex_ht, FUTEX_HT_SIZE, 1, &futex_ht_ops);
00088 }
00089
00094 void futex_initialize(futex_t *futex)
00095 {
00096 waitq_initialize(&futex->wq);
00097 link_initialize(&futex->ht_link);
00098 futex->paddr = 0;
00099 futex->refcount = 1;
00100 }
00101
00111 __native sys_futex_sleep_timeout(__address uaddr, __u32 usec, int flags)
00112 {
00113 futex_t *futex;
00114 __address paddr;
00115 pte_t *t;
00116 ipl_t ipl;
00117
00118 ipl = interrupts_disable();
00119
00120
00121
00122
00123 page_table_lock(AS, true);
00124 t = page_mapping_find(AS, ALIGN_DOWN(uaddr, PAGE_SIZE));
00125 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
00126 page_table_unlock(AS, true);
00127 interrupts_restore(ipl);
00128 return (__native) ENOENT;
00129 }
00130 paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
00131 page_table_unlock(AS, true);
00132
00133 interrupts_restore(ipl);
00134
00135 futex = futex_find(paddr);
00136
00137 return (__native) waitq_sleep_timeout(&futex->wq, usec, flags | SYNCH_FLAGS_INTERRUPTIBLE);
00138 }
00139
00146 __native sys_futex_wakeup(__address uaddr)
00147 {
00148 futex_t *futex;
00149 __address paddr;
00150 pte_t *t;
00151 ipl_t ipl;
00152
00153 ipl = interrupts_disable();
00154
00155
00156
00157
00158 page_table_lock(AS, true);
00159 t = page_mapping_find(AS, ALIGN_DOWN(uaddr, PAGE_SIZE));
00160 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
00161 page_table_unlock(AS, true);
00162 interrupts_restore(ipl);
00163 return (__native) ENOENT;
00164 }
00165 paddr = PTE_GET_FRAME(t) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
00166 page_table_unlock(AS, true);
00167
00168 interrupts_restore(ipl);
00169
00170 futex = futex_find(paddr);
00171
00172 waitq_wakeup(&futex->wq, WAKEUP_FIRST);
00173
00174 return 0;
00175 }
00176
00185 futex_t *futex_find(__address paddr)
00186 {
00187 link_t *item;
00188 futex_t *futex;
00189 btree_node_t *leaf;
00190
00191
00192
00193
00194
00195 rwlock_read_lock(&futex_ht_lock);
00196 item = hash_table_find(&futex_ht, &paddr);
00197 if (item) {
00198 futex = hash_table_get_instance(item, futex_t, ht_link);
00199
00200
00201
00202
00203 mutex_lock(&TASK->futexes_lock);
00204 if (!btree_search(&TASK->futexes, paddr, &leaf)) {
00205
00206
00207
00208
00209
00210 mutex_unlock(&TASK->futexes_lock);
00211 goto gain_write_access;
00212 }
00213 mutex_unlock(&TASK->futexes_lock);
00214
00215 rwlock_read_unlock(&futex_ht_lock);
00216 } else {
00217 gain_write_access:
00218
00219
00220
00221
00222
00223 rwlock_read_unlock(&futex_ht_lock);
00224
00225 rwlock_write_lock(&futex_ht_lock);
00226
00227
00228
00229
00230 item = hash_table_find(&futex_ht, &paddr);
00231 if (item) {
00232 futex = hash_table_get_instance(item, futex_t, ht_link);
00233
00234
00235
00236
00237 mutex_lock(&TASK->futexes_lock);
00238 if (!btree_search(&TASK->futexes, paddr, &leaf)) {
00239
00240
00241
00242
00243
00244 futex->refcount++;
00245 btree_insert(&TASK->futexes, paddr, futex, leaf);
00246 }
00247 mutex_unlock(&TASK->futexes_lock);
00248
00249 rwlock_write_unlock(&futex_ht_lock);
00250 } else {
00251 futex = (futex_t *) malloc(sizeof(futex_t), 0);
00252 futex_initialize(futex);
00253 futex->paddr = paddr;
00254 hash_table_insert(&futex_ht, &paddr, &futex->ht_link);
00255
00256
00257
00258
00259
00260
00261 mutex_lock(&TASK->futexes_lock);
00262 btree_insert(&TASK->futexes, paddr, futex, NULL);
00263 mutex_unlock(&TASK->futexes_lock);
00264
00265 rwlock_write_unlock(&futex_ht_lock);
00266 }
00267 }
00268
00269 return futex;
00270 }
00271
00278 index_t futex_ht_hash(__native *key)
00279 {
00280 return *key & (FUTEX_HT_SIZE-1);
00281 }
00282
00289 bool futex_ht_compare(__native *key, count_t keys, link_t *item)
00290 {
00291 futex_t *futex;
00292
00293 ASSERT(keys == 1);
00294
00295 futex = hash_table_get_instance(item, futex_t, ht_link);
00296 return *key == futex->paddr;
00297 }
00298
00303 void futex_ht_remove_callback(link_t *item)
00304 {
00305 futex_t *futex;
00306
00307 futex = hash_table_get_instance(item, futex_t, ht_link);
00308 free(futex);
00309 }
00310
00312 void futex_cleanup(void)
00313 {
00314 link_t *cur;
00315
00316 rwlock_write_lock(&futex_ht_lock);
00317 mutex_lock(&TASK->futexes_lock);
00318
00319 for (cur = TASK->futexes.leaf_head.next; cur != &TASK->futexes.leaf_head; cur = cur->next) {
00320 btree_node_t *node;
00321 int i;
00322
00323 node = list_get_instance(cur, btree_node_t, leaf_link);
00324 for (i = 0; i < node->keys; i++) {
00325 futex_t *ftx;
00326 __address paddr = node->key[i];
00327
00328 ftx = (futex_t *) node->value[i];
00329 if (--ftx->refcount == 0)
00330 hash_table_remove(&futex_ht, &paddr, 1);
00331 }
00332 }
00333
00334 mutex_unlock(&TASK->futexes_lock);
00335 rwlock_write_unlock(&futex_ht_lock);
00336 }
00337