summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPatrick Williams <iawillia@us.ibm.com>2010-06-11 21:40:31 -0500
committerPatrick Williams <iawillia@us.ibm.com>2010-06-11 21:40:31 -0500
commit24e81bc664f5cdbfc8be1badf00b025ec122af00 (patch)
tree2d41e3305fb903024541d105dfec6adf1824839a /src
parent165e6bed506f9fddd7e9da8ad1f4c7f186e29b00 (diff)
downloadtalos-hostboot-24e81bc664f5cdbfc8be1badf00b025ec122af00.tar.gz
talos-hostboot-24e81bc664f5cdbfc8be1badf00b025ec122af00.zip
Add mutex userspace / syscalls.
Diffstat (limited to 'src')
-rw-r--r--src/include/kernel/syscalls.H5
-rw-r--r--src/include/kernel/usermutex.H16
-rw-r--r--src/include/sys/mutex.h20
-rw-r--r--src/include/sys/task.h8
-rw-r--r--src/include/util/locked/lock.H20
-rw-r--r--src/include/util/locked/queue.H33
-rw-r--r--src/kernel/syscall.C66
-rw-r--r--src/lib/makefile2
-rw-r--r--src/lib/syscall_mutex.C33
-rw-r--r--src/lib/syscall_task.C9
-rw-r--r--src/sys/init/init_main.C9
11 files changed, 204 insertions, 17 deletions
diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H
index 826ac93b9..ebe7d0059 100644
--- a/src/include/kernel/syscalls.H
+++ b/src/include/kernel/syscalls.H
@@ -10,6 +10,11 @@ namespace Systemcalls
TASK_END,
TASK_GETTID,
+ MUTEX_CREATE,
+ MUTEX_DESTROY,
+ MUTEX_LOCK_CONTESTED,
+ MUTEX_UNLOCK_CONTESTED,
+
SYSCALL_MAX
};
};
diff --git a/src/include/kernel/usermutex.H b/src/include/kernel/usermutex.H
new file mode 100644
index 000000000..3dcd904b4
--- /dev/null
+++ b/src/include/kernel/usermutex.H
@@ -0,0 +1,16 @@
+#ifndef __KERNEL_USERMUTEX_H
+#define __KERNEL_USERMUTEX_H
+
+#include <util/locked/queue.H>
+#include <kernel/spinlock.H>
+#include <kernel/task.H>
+
+struct UserMutex
+{
+ uint64_t value;
+ bool unlock_pend;
+ Spinlock lock;
+ Util::Locked::Queue<task_t> waiting;
+};
+
+#endif
diff --git a/src/include/sys/mutex.h b/src/include/sys/mutex.h
new file mode 100644
index 000000000..3eca65f06
--- /dev/null
+++ b/src/include/sys/mutex.h
@@ -0,0 +1,20 @@
+#ifndef __SYS_MUTEX_H
+#define __SYS_MUTEX_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef void* mutex_t;
+
+mutex_t mutex_create();
+int mutex_destroy(mutex_t);
+
+int mutex_lock(mutex_t);
+int mutex_unlock(mutex_t);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/include/sys/task.h b/src/include/sys/task.h
index 84ddb10f9..fa9838723 100644
--- a/src/include/sys/task.h
+++ b/src/include/sys/task.h
@@ -1,18 +1,20 @@
#ifndef __SYS_TASK_H
#define __SYS_TASK_H
-#include <sys/syscall.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
+typedef uint64_t tid_t;
+
void task_yield();
-int task_create(void(*)(void*), void*);
+tid_t task_create(void(*)(void*), void*);
void task_end();
-uint64_t task_gettid();
+tid_t task_gettid();
#ifdef __cplusplus
}
diff --git a/src/include/util/locked/lock.H b/src/include/util/locked/lock.H
index b5237276e..05da95900 100644
--- a/src/include/util/locked/lock.H
+++ b/src/include/util/locked/lock.H
@@ -14,6 +14,26 @@ namespace Util
virtual void lock() = 0;
virtual void unlock() = 0;
};
+
+ template<bool _locked, typename _T>
+ class LockHelper
+ {
+ public:
+ inline LockHelper(_T& i) : l(i) {};
+ inline void lock() { l.lock(); };
+ inline void unlock() { l.unlock(); };
+ private:
+ _T& l;
+ };
+
+ template<typename _T>
+ class LockHelper<false,_T>
+ {
+ public:
+ inline LockHelper(_T&i) {};
+ inline void lock() {};
+ inline void unlock() {};
+ };
};
};
diff --git a/src/include/util/locked/queue.H b/src/include/util/locked/queue.H
index 2f230819e..51d2c430e 100644
--- a/src/include/util/locked/queue.H
+++ b/src/include/util/locked/queue.H
@@ -1,6 +1,8 @@
#ifndef __UTIL_LOCKED_QUEUE_H
#define __UTIL_LOCKED_QUEUE_H
+#include <util/locked/lock.H>
+
namespace Util
{
namespace Locked
@@ -21,6 +23,9 @@ namespace Util
_S lock;
+ void __lock();
+ void __unlock();
+
};
template <typename _T, bool locked, typename _S>
@@ -28,8 +33,7 @@ namespace Util
{
_T* item = NULL;
- if (locked)
- lock.lock();
+ __lock();
if (tail != NULL)
{
@@ -40,17 +44,15 @@ namespace Util
tail = item->prev;
}
- if (locked)
- lock.unlock();
-
+ __unlock();
+
return item;
}
template <typename _T, bool locked, typename _S>
void Queue<_T,locked,_S>::insert(_T* item)
{
- if (locked)
- lock.lock();
+ __lock();
if (head == NULL)
{
@@ -63,10 +65,23 @@ namespace Util
item->next = head;
head = head->prev = item;
}
+
+ __unlock();
+ }
- if (locked)
- lock.unlock();
+ template <typename _T, bool locked, typename _S>
+ void Queue<_T,locked,_S>::__lock()
+ {
+ Util::Locked::LockHelper<locked,_S>(lock).lock();
+ }
+
+ template <typename _T, bool locked, typename _S>
+ void Queue<_T,locked,_S>::__unlock()
+ {
+ Util::Locked::LockHelper<locked,_S>(lock).unlock();
}
+
+
};
};
diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C
index b993bf222..ce26970c7 100644
--- a/src/kernel/syscall.C
+++ b/src/kernel/syscall.C
@@ -6,6 +6,7 @@
#include <kernel/syscalls.H>
#include <kernel/console.H>
#include <kernel/pagemgr.H>
+#include <kernel/usermutex.H>
extern "C"
void kernel_execute_decrementer()
@@ -26,6 +27,10 @@ namespace Systemcalls
void TaskStart(task_t*);
void TaskEnd(task_t*);
void TaskGettid(task_t*);
+ void MutexCreate(task_t*);
+ void MutexDestroy(task_t*);
+ void MutexLockCont(task_t*);
+ void MutexUnlockCont(task_t*);
syscall syscalls[] =
{
@@ -33,6 +38,11 @@ namespace Systemcalls
&TaskStart,
&TaskEnd,
&TaskGettid,
+
+ &MutexCreate,
+ &MutexDestroy,
+ &MutexLockCont,
+ &MutexUnlockCont,
};
};
@@ -103,4 +113,60 @@ namespace Systemcalls
{
TASK_SETRTN(t, t->tid);
}
+
+ void MutexCreate(task_t* t)
+ {
+ UserMutex * m = new UserMutex();
+ TASK_SETRTN(t, (uint64_t)m);
+ }
+
+ void MutexDestroy(task_t* t)
+ {
+ // TODO: Extra verification of parameter and mutex state.
+
+ delete (UserMutex*) TASK_GETARG0(t);
+ TASK_SETRTN(t, 0);
+ }
+
+ void MutexLockCont(task_t* t)
+ {
+ // TODO: Extra verification of parameter and mutex state.
+
+ UserMutex* m = (UserMutex*) TASK_GETARG0(t);
+ m->lock.lock();
+ if (m->unlock_pend)
+ {
+ // We missed the unlock syscall, take lock and return to userspace.
+ m->unlock_pend = false;
+ m->lock.unlock();
+
+ }
+ else
+ {
+ // Queue ourself to wait for unlock.
+ m->waiting.insert(TaskManager::getCurrentTask());
+ m->lock.unlock();
+ CpuManager::getCurrentCPU()->scheduler->setNextRunnable();
+ }
+ TASK_SETRTN(t, 0);
+ }
+
+ void MutexUnlockCont(task_t* t)
+ {
+ // TODO: Extra verification of parameter and mutex state.
+
+ UserMutex* m = (UserMutex*) TASK_GETARG0(t);
+ m->lock.lock();
+ task_t* wait_task = m->waiting.remove();
+ if (NULL == wait_task)
+ {
+ m->unlock_pend = true;
+ }
+ else
+ {
+ wait_task->cpu->scheduler->addTask(wait_task);
+ }
+ m->lock.unlock();
+ TASK_SETRTN(t, 0);
+ }
};
diff --git a/src/lib/makefile b/src/lib/makefile
index 1071dc75e..718a8219e 100644
--- a/src/lib/makefile
+++ b/src/lib/makefile
@@ -2,7 +2,7 @@ OBJDIR = ../../obj
include ../../config.mk
OBJS = string.o stdlib.o
-OBJS += syscall_stub.o syscall_task.o
+OBJS += syscall_stub.o syscall_task.o syscall_mutex.o
OBJECTS = $(addprefix ${OBJDIR}/, ${OBJS})
all: ${OBJECTS}
diff --git a/src/lib/syscall_mutex.C b/src/lib/syscall_mutex.C
new file mode 100644
index 000000000..8ac392792
--- /dev/null
+++ b/src/lib/syscall_mutex.C
@@ -0,0 +1,33 @@
+#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/syscall_task.C b/src/lib/syscall_task.C
index bfd522933..d07ea3f19 100644
--- a/src/lib/syscall_task.C
+++ b/src/lib/syscall_task.C
@@ -1,4 +1,5 @@
#include <sys/task.h>
+#include <sys/syscall.h>
#include <kernel/task.H>
using namespace Systemcalls;
@@ -9,9 +10,9 @@ void task_yield()
return;
}
-int task_create(void(*fn)(void*), void* ptr)
+tid_t task_create(void(*fn)(void*), void* ptr)
{
- return (int64_t) _syscall2(TASK_START, (void*)fn, ptr);
+ return (tid_t) _syscall2(TASK_START, (void*)fn, ptr);
}
void task_end()
@@ -20,7 +21,7 @@ void task_end()
return;
}
-uint64_t task_gettid()
+tid_t task_gettid()
{
- return (uint64_t)_syscall0(TASK_GETTID);
+ return (tid_t)_syscall0(TASK_GETTID);
}
diff --git a/src/sys/init/init_main.C b/src/sys/init/init_main.C
index 8be5ae6c3..efeddcafd 100644
--- a/src/sys/init/init_main.C
+++ b/src/sys/init/init_main.C
@@ -1,10 +1,15 @@
#include <kernel/console.H> // TODO : Remove this.
#include <sys/task.h>
+#include <sys/mutex.h>
+
+mutex_t global_mutex;
void init_child(void* unused)
{
+ mutex_lock(global_mutex);
printk("Here I am %d\n", task_gettid());
+ mutex_unlock(global_mutex);
task_end();
}
@@ -12,10 +17,14 @@ void init_main(void* unused)
{
printk("Starting init!\n");
+ global_mutex = mutex_create();
+
while(1)
{
+ mutex_lock(global_mutex);
int t = task_create(&init_child, NULL);
printk("Created child %d\n", t);
for (volatile int i = 0 ; i < 10000000; i++);
+ mutex_unlock(global_mutex);
}
}
OpenPOWER on IntegriCloud