commit 2495223bb4a77539f2060d7b18038bdd3664e090
parent 72c0ea32616df5f6e4054a6e2cefb1801679a365
Author: oblique <psyberbits@gmail.com>
Date: Mon, 5 Nov 2012 18:07:44 +0200
improved and safer semaphores
Diffstat:
1 file changed, 26 insertions(+), 34 deletions(-)
diff --git a/include/semaphore.h b/include/semaphore.h
@@ -2,22 +2,25 @@
#define __SEMAPHORE_H
#include <io.h>
+#include <spinlock.h>
#include <sched.h>
typedef struct {
u32 counter;
+ spinlock_t lock;
} semaphore_t;
typedef struct {
semaphore_t sem;
} mutex_t;
-#define SEMAPHORE_INIT(v) { (v) }
+#define SEMAPHORE_INIT(v) { (v), SPINLOCK_INIT }
static inline void
semaphore_init(semaphore_t *sem, u32 value)
{
sem->counter = value;
+ INIT_SPINLOCK(&sem->lock);
}
/* returns 1 if managed to decreased the counter
@@ -25,53 +28,42 @@ semaphore_init(semaphore_t *sem, u32 value)
static inline int
semaphore_trywait(semaphore_t *sem)
{
- u32 tmp;
-
- asm volatile (
- "ldrex v1, [%1] \n\t"
- "teq v1, #0 \n\t"
- "moveq %0, #1 \n\t"
- "subne v1, v1, #1 \n\t"
- "strexne %0, v1, [%1] \n\t"
- : "=&r" (tmp)
- : "r" (&sem->counter)
- : "v1", "memory", "cc"
- );
-
- if (tmp == 0) {
- dmb();
- return 1;
- } else
+ spinlock_lock(&sem->lock);
+ if (sem->counter == 0) {
+ spinlock_unlock(&sem->lock);
return 0;
+ }
+ sem->counter--;
+ spinlock_unlock(&sem->lock);
+ return 1;
}
/* blocks until it manage to decrease the counter */
static inline void
semaphore_wait(semaphore_t *sem)
{
- while (!semaphore_trywait(sem))
- suspend_task((u32)sem); /* sleep */
+ while (1) {
+ spinlock_lock(&sem->lock);
+ if (sem->counter == 0) {
+ suspend_task_no_schedule((u32)sem);
+ spinlock_unlock(&sem->lock);
+ schedule();
+ continue;
+ }
+ sem->counter--;
+ spinlock_unlock(&sem->lock);
+ break;
+ }
}
/* increases the counter and resumes other tasks */
static inline void
semaphore_done(semaphore_t *sem)
{
- dmb();
- asm volatile (
- "1: \n\t"
- "ldrex v1, [%0] \n\t"
- "add v1, v1, #1 \n\t"
- "strex v2, v1, [%0] \n\t"
- "teq v2, #0 \n\t"
- "bne 1b \n\t"
- :
- : "r" (&sem->counter)
- : "v1", "v2", "memory", "cc"
- );
- dmb();
- /* resume tasks that use the same semaphore */
+ spinlock_lock(&sem->lock);
+ sem->counter++;
resume_tasks((u32)sem);
+ spinlock_unlock(&sem->lock);
}