#include "tera_sync.h" #include #include extern ti_mutex_t thread_list_lock; /*************************************************************************/ /* */ /* Contains all the Tera synchronization routines except for barriers. */ /* */ /*************************************************************************/ /***** Block the current thread and broadcast release all threads. *****/ /* Alternating block mechanism to prevent race conditions. With only one block variable, it's difficult to know when to reset the block variable; you want to make sure everyone's out of the lock, but you don't want anyone getting ahead of the game and skipping the next block. With this mechanism, the next block is guaranteed to be blocking before you release the threads out of the current block. */ static future int block1$, block2$; static int toggle; static void init_blocking() { purge(&block1$); purge(&block2$); toggle = 0; } static void block1() { readff(&block1$); } static void block2() { readff(&block2$); } static void release1() { toggle = !toggle; writexf(&block1$,1); } static void release2() { toggle = !toggle; writexf(&block2$,1); } void tera_block() { if (toggle) { block1(); } else { block2(); } } void tera_broadcast_release() { if (toggle) { purge(&block2$); release1(); } else { purge(&block1$); release2(); } } #if 0 static int release_count; static future int block$, done$; static void init_blocking() { purge(&block$); purge(&done$); release_count = 0; } /* Blocks the current thread. */ void tera_block() { purge(&done$); int_fetch_add(&release_count, 1); /* Count how many are waiting. */ if (block$ == 1) { /* Block here on this future variable. */ /* We want to wait for everyone to get out before resetting the block variable. */ if (int_fetch_add(&release_count, -1)) { readff(&done$); } else { writexf(&done$); } /* int_fetch_add(&release_count, -1); while (int_fetch_add(&release_count, 0)) {} */ purge(&block$); return; } } /* Releases all threads. */ void tera_broadcast_release() { writexf(&block$,1); /* We want to wait for everyone to get out before resetting the block variable. */ if (int_fetch_add(&release_count, 0)) { readff(&done$); } else { writefx(&done$); } /* while (int_fetch_add(&release_count, 0) != 0) {} */ purge(&block$); } #endif /***** Set or get the current task ID. Inline these, maybe. *****/ /* Make sure the pointer you pass in doesn't dangle. */ void tera_set_task_id(int *id_p) { terart_register_task_data((void *)id_p); } /* Argh. This is like dealing with magnetic core memory. Is there a better way??? */ int tera_get_task_id() { int *tmp = 0; tmp = (int *)terart_register_task_data(tmp); terart_register_task_data(tmp); return *tmp; } int tera_thread_equal(int id) { return id == tera_get_task_id(); } /***** The barrier implementation is in barrier.c. *****/ /***** Mutexes. *****/ int tera_mutex_init(ti_mutex_t *lock) { assert(lock); writexf(&(lock->lock$), 1); return 0; } int tera_mutex_lock(ti_mutex_t *lock) { int x; x = lock->lock$; return 0; } int tera_mutex_unlock(ti_mutex_t *lock) { lock->lock$ = 1; return 0; } void tera_mutex_alloc_lock(ti_mutex_t **lock) { *lock = (ti_mutex_t *)malloc(sizeof(ti_mutex_t)); tera_mutex_init(*lock); } int tera_mutex_destroy(ti_mutex_t *lock) { return 0; } /***** Condition variables. *****/ int tera_cond_destroy(ti_cond_t *cond) { /* The man page says that the user will free the memory. Question: what's going to happen when the user frees memory that has its full-empty bits marked or unmarked? Will the thread block? Ow. Let's read the techy systems stuff to find out. */ return 0; } int tera_cond_init(ti_cond_t *cond, ti_cond_attr *foo) { writexf(&(cond->lock$), 1); cond->waiters = 0; return 0; } int tera_cond_broadcast(ti_cond_t *cond) { while (int_fetch_add(&(cond->waiters),0)) { tera_cond_signal(cond); } return 0; } int tera_cond_signal(ti_cond_t *cond) { cond->lock$ = 1; return 0; } int tera_cond_timedwait(ti_cond_t *cond, ti_mutex_t *lock) { /* No idea how to do this right now. */ int foo; tera_mutex_unlock(lock); int_fetch_add(&(cond->waiters), 1); foo = cond->lock$; tera_mutex_lock(lock); return 0; } int tera_cond_wait(ti_cond_t *cond, ti_mutex_t *lock) { int foo; tera_mutex_unlock(lock); int_fetch_add(&(cond->waiters), 1); foo = cond->lock$; int_fetch_add(&(cond->waiters), -1); tera_mutex_lock(lock); return 0; } /***** Initialization. *****/ void tera_init() { init_blocking(); barrier_init(); tera_dtoa_mutex_init(); writexf(&(thread_list_lock.lock$),1); }