diff options
author | dgilbert <dgilbert@us.ibm.com> | 2011-06-03 12:54:41 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2011-06-17 12:23:52 -0500 |
commit | 609d6810b8bc92dc979f8bbb8e7e7d7b7b5d9490 (patch) | |
tree | cd517ec2e10a95638e675b037bb24e2d01296ef4 /src/lib | |
parent | f64ba52098e248e62b4ddb14c0a027c21066e9e2 (diff) | |
download | talos-hostboot-609d6810b8bc92dc979f8bbb8e7e7d7b7b5d9490.tar.gz talos-hostboot-609d6810b8bc92dc979f8bbb8e7e7d7b7b5d9490.zip |
Initial futex support
Change-Id: I51a4f1117085ce23c7993c1a38e4124596636726
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/141
Tested-by: Jenkins Server
Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com>
Reviewed-by: Thi N. Tran <thi@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/makefile | 6 | ||||
-rw-r--r-- | src/lib/sync.C | 160 | ||||
-rw-r--r-- | src/lib/syscall_mmio.C | 4 | ||||
-rw-r--r-- | src/lib/syscall_mutex.C | 33 | ||||
-rw-r--r-- | src/lib/test/makefile | 6 | ||||
-rw-r--r-- | src/lib/test/synctest.H | 93 |
6 files changed, 265 insertions, 37 deletions
diff --git a/src/lib/makefile b/src/lib/makefile index d15ca3bef..3fdb3a8b1 100644 --- a/src/lib/makefile +++ b/src/lib/makefile @@ -1,7 +1,9 @@ ROOTPATH = ../.. OBJS = string.o stdlib.o assert.o stdio.o -OBJS += syscall_stub.o syscall_task.o syscall_mutex.o syscall_msg.o -OBJS += syscall_mmio.o syscall_time.o +OBJS += syscall_stub.o syscall_task.o syscall_msg.o +OBJS += syscall_mmio.o syscall_time.o sync.o + +SUBDIRS = test.d include ${ROOTPATH}/config.mk diff --git a/src/lib/sync.C b/src/lib/sync.C new file mode 100644 index 000000000..a70761eef --- /dev/null +++ b/src/lib/sync.C @@ -0,0 +1,160 @@ +#include <sys/sync.h> +#include <sys/syscall.h> +#include <assert.h> + +using namespace Systemcalls; + +//----------------------------------------------------------------------------- + +uint64_t futex_wait(uint64_t * i_addr, uint64_t i_val) +{ + return (uint64_t) _syscall2(FUTEX_WAIT,i_addr, (void *)i_val); +} + +//----------------------------------------------------------------------------- + +uint64_t futex_wake(uint64_t * i_addr, uint64_t i_count) +{ + return (uint64_t) _syscall2(FUTEX_WAKE, i_addr, (void *)i_count); +} + +//----------------------------------------------------------------------------- + +void barrier_init (barrier_t * o_barrier, uint64_t i_count) +{ + mutex_init(&(o_barrier->iv_mutex)); + o_barrier->iv_event = 0; + o_barrier->iv_count = i_count; + o_barrier->iv_missing = i_count; + return; +} + +//----------------------------------------------------------------------------- + +void barrier_destroy (barrier_t * i_barrier) +{ + assert(i_barrier->iv_missing == i_barrier->iv_count); + return; +} + +//----------------------------------------------------------------------------- + +void barrier_wait (barrier_t * i_barrier) +{ + mutex_lock(&(i_barrier->iv_mutex)); + --(i_barrier->iv_missing); + if(i_barrier->iv_missing > 0) + { + uint64_t l_event = i_barrier->iv_event; + mutex_unlock(&(i_barrier->iv_mutex)); + do + { + futex_wait(&(i_barrier->iv_event), l_event); + } while (i_barrier->iv_event == l_event); + } + else + { + ++(i_barrier->iv_event); + i_barrier->iv_missing = i_barrier->iv_count; + + // Wake em all up + futex_wake(&(i_barrier->iv_event), UINT64_MAX); + mutex_unlock(&(i_barrier->iv_mutex)); + } + return; +} + +//----------------------------------------------------------------------------- + +mutex_t * mutex_create() +{ + mutex_t * m = new mutex_t; + mutex_init(m); + return m; +} + +//----------------------------------------------------------------------------- + +void mutex_init(mutex_t * o_mutex) +{ + o_mutex->iv_val = 0; + return; +} + +//----------------------------------------------------------------------------- + +void mutex_destroy(mutex_t *& i_mutex) +{ + delete i_mutex; + i_mutex = NULL; + return; +} + +//----------------------------------------------------------------------------- + +void mutex_lock(mutex_t * i_mutex) +{ +#ifdef __IDEA_1 + uint64_t l_count = __sync_val_compare_and_swap(&(i_mutex->iv_val),0,1); + + if(l_count != 0) + { + if (l_count != 2) + l_count = __sync_lock_test_and_set(&(i_mutex->iv_val), 2); + + while( l_count != 0 ) + { + futex_wait( &(i_mutex->iv_val), 2); + l_count = __sync_lock_test_and_set(&(i_mutex->iv_val),2); + // if more than one thread gets out - one continues while + // the rest get blocked again. + } + } +#endif + + // Idea # 2 + while(1) + { + uint64_t l_count = __sync_val_compare_and_swap(&(i_mutex->iv_val),0,1); + if( 0 == l_count ) // uncontended lock + { + break; + } + else if ( 2 == l_count ) // already contended + { + futex_wait( &(i_mutex->iv_val), l_count); + } + else if ( 1 == l_count ) // lock now contended + { + if (__sync_bool_compare_and_swap(&(i_mutex->iv_val),1,2)) + { + futex_wait( &(i_mutex->iv_val), 2); + } + } + } + + return; +} + +//----------------------------------------------------------------------------- + +void mutex_unlock(mutex_t * i_mutex) +{ +#ifdef __IDEA_1 + if (__sync_fetch_and_sub(&(i_mutex->iv_val), 1) != 1) + { + i_mutex->iv_val = 0; // the thread that is started will set this back to 2 + futex_wake(&(i_mutex->iv_val), 1); // wake one thread + } +#endif + // #idea 2 + uint64_t l_count = __sync_lock_test_and_set(&(i_mutex->iv_val),0); + if(2 == l_count) + { + futex_wake(&(i_mutex->iv_val), 1); // wake one thread + } + + return; +} + + diff --git a/src/lib/syscall_mmio.C b/src/lib/syscall_mmio.C index 83498798b..91e4e113b 100644 --- a/src/lib/syscall_mmio.C +++ b/src/lib/syscall_mmio.C @@ -26,7 +26,7 @@ int mmio_hmer_write(uint64_t value) return (int)(int64_t)_syscall1(MMIO_HMER_WRITE, (void*)value); } -mutex_t mmio_xscom_mutex() +mutex_t * mmio_xscom_mutex() { // Get task structure. register task_t* task; @@ -36,7 +36,7 @@ mutex_t mmio_xscom_mutex() assert(task->affinity_pinned); // Get mutex from cpu structure. - mutex_t mutex = task->cpu->xscom_mutex; + mutex_t * mutex = task->cpu->xscom_mutex; // Create mutex if not created. if (NULL == mutex) diff --git a/src/lib/syscall_mutex.C b/src/lib/syscall_mutex.C deleted file mode 100644 index 8ac392792..000000000 --- a/src/lib/syscall_mutex.C +++ /dev/null @@ -1,33 +0,0 @@ -#include <sys/mutex.h> -#include <sys/syscall.h> -#include <kernel/usermutex.H> - -using namespace Systemcalls; - -mutex_t mutex_create() -{ - return (mutex_t) _syscall0(MUTEX_CREATE); -} - -int mutex_destroy(mutex_t m) -{ - return (int64_t)_syscall1(MUTEX_DESTROY, m); -} - -int mutex_lock(mutex_t m) -{ - uint64_t oldvalue = __sync_fetch_and_add(&((UserMutex*)m)->value, 1); - if (0 == oldvalue) - return 0; - else - return (int64_t)_syscall1(MUTEX_LOCK_CONTESTED, m); -} - -int mutex_unlock(mutex_t m) -{ - uint64_t oldvalue = __sync_fetch_and_sub(&((UserMutex*)m)->value, 1); - if (1 == oldvalue) - return 0; - else - return (int64_t)_syscall1(MUTEX_UNLOCK_CONTESTED, m); -} diff --git a/src/lib/test/makefile b/src/lib/test/makefile new file mode 100644 index 000000000..723f4b36b --- /dev/null +++ b/src/lib/test/makefile @@ -0,0 +1,6 @@ +ROOTPATH = ../../.. + +MODULE = testsyslib +TESTS = *.H + +include ${ROOTPATH}/config.mk diff --git a/src/lib/test/synctest.H b/src/lib/test/synctest.H new file mode 100644 index 000000000..5a53d2e0a --- /dev/null +++ b/src/lib/test/synctest.H @@ -0,0 +1,93 @@ +#ifndef __SYNCTEST_H +#define __SYNCTEST_H +/** + * @file synctest.H + * + * @brief Test cases for the sycronization +*/ + +#include <cxxtest/TestSuite.H> +#include <sys/sync.h> +#include <sys/task.h> + +class SyncTest: public CxxTest::TestSuite +{ + public: + + + void testMutex() + { + mutex_init(&mutex); + barrier_init(&barrier, 7); + + task_create(func1, this); + task_create(func2, this); + task_create(func2, this); + task_create(func2, this); + task_create(func2, this); + task_create(func2, this); + barrier_wait(&barrier); + TS_TRACE("ALL THREADS ENDED"); + } + + void testBarrier() + { + barrier_t barrier; + barrier_init(&barrier,3); + task_create(func3,&barrier); + task_create(func4,&barrier); + barrier_wait(&barrier); + TS_TRACE("B0"); + barrier_destroy(&barrier); + } + + private: + + mutex_t mutex; + barrier_t barrier; + + static void func1(void * i_p) + { + SyncTest * my = (SyncTest *) i_p; + mutex_t * mutex = &(my->mutex); + barrier_t * barrier = &(my->barrier); + + mutex_lock(mutex); + for(int i = 0; i < 100000; ++i); + TS_TRACE("ME FIRST"); + mutex_unlock(mutex); + barrier_wait(barrier); + task_end(); + } + + static void func2(void * i_p) + { + SyncTest * my = (SyncTest *) i_p; + mutex_t * mutex = &(my->mutex); + barrier_t * barrier = &(my->barrier); + + mutex_lock(mutex); + TS_TRACE("ME NEXT"); + mutex_unlock(mutex); + barrier_wait(barrier); + task_end(); + } + + static void func3(void * i_p) + { + barrier_t * barrier = (barrier_t *) i_p; + barrier_wait(barrier); + TS_TRACE("B1"); + task_end(); + } + static void func4(void * i_p) + { + barrier_t * barrier = (barrier_t *) i_p; + barrier_wait(barrier); + TS_TRACE("B2"); + task_end(); + } + +}; +#endif + |