--- /dev/null
+#include <config.h>
+#include <corax/types.h>
+#include <corax/errno.h>
+#include <spinlock.h>
+#include <arch.h>
+#include <sched.h>
+#include <sem.h>
+
+inline static int _nq(sem_t *sem, task_t *t)
+{
+ int i;
+
+ for(i = 0; i < CONFIG_SEM_WAITQLEN; i++) {
+ if(!sem->sem_waitq[i]) {
+ sem->sem_waitq[i] = t;
+ return(i);
+ }
+ }
+
+ return(-ENOMEM);
+}
+
+inline static void _wakeup_all(sem_t *sem)
+{
+ int i;
+
+ for(i = 0; i < CONFIG_SEM_WAITQLEN; i++) {
+ if(sem->sem_waitq[i]) {
+ sched_wakeup(sem->sem_waitq[i], 0);
+ }
+ }
+
+ return;
+}
+
+int sem_wait(sem_t *sem)
+{
+ task_t *ctask;
+ int ret_val;
+ int slot;
+
+ ctask = task_get_current();
+ ret_val = -EAGAIN;
+ slot = -1;
+
+ do {
+ spinlock_lock(&(sem->sem_lock));
+
+ if(sem->sem_count > 0) {
+ /* count is positive - we can proceed */
+ sem->sem_count--;
+
+ /* if we had been in the queue, clean up our slot */
+ if(slot >= 0) {
+ sem->sem_waitq[slot] = NULL;
+ }
+
+ ret_val = 0;
+ } else {
+ /* we have to wait */
+
+ if(slot < 0) {
+ /* get a slot in the wait queue */
+ slot = _nq(sem, ctask);
+ }
+ }
+
+ spinlock_unlock(&(sem->sem_lock));
+
+ if(slot >= 0) {
+ /*
+ * If we have a valid slot, go to bed and wait for
+ * someone to wake us up.
+ */
+ sched_sleep(NULL);
+ }
+
+ } while(ret_val < 0);
+
+ return(ret_val);
+}
+
+int sem_trywait(sem_t *sem)
+{
+ int ret_val;
+
+ ret_val = -EAGAIN;
+
+ spinlock_lock(&(sem->sem_lock));
+
+ if(sem->sem_count > 0) {
+ sem->sem_count--;
+ ret_val = 0;
+ }
+
+ spinlock_unlock(&(sem->sem_lock));
+
+ return(ret_val);
+}
+
+int sem_post(sem_t *sem)
+{
+ int new_count;
+ int ret_val;
+
+ ret_val = -EOVERFLOW;
+
+ spinlock_lock(&(sem->sem_lock));
+
+ new_count = sem->sem_count + 1;
+
+ /* make sure the counter doesn't overflow */
+ if(new_count > sem->sem_count) {
+ sem->sem_count = new_count;
+ _wakeup_all(sem);
+
+ ret_val = 0;
+ }
+
+ spinlock_unlock(&(sem->sem_lock));
+
+ return(ret_val);
+}