summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authordgilbert <dgilbert@us.ibm.com>2011-06-03 12:54:41 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2011-06-17 12:23:52 -0500
commit609d6810b8bc92dc979f8bbb8e7e7d7b7b5d9490 (patch)
treecd517ec2e10a95638e675b037bb24e2d01296ef4 /src/lib
parentf64ba52098e248e62b4ddb14c0a027c21066e9e2 (diff)
downloadtalos-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/makefile6
-rw-r--r--src/lib/sync.C160
-rw-r--r--src/lib/syscall_mmio.C4
-rw-r--r--src/lib/syscall_mutex.C33
-rw-r--r--src/lib/test/makefile6
-rw-r--r--src/lib/test/synctest.H93
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
+
OpenPOWER on IntegriCloud