summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/lm4/task.c46
-rw-r--r--include/task.h15
-rw-r--r--include/task_id.h1
3 files changed, 62 insertions, 0 deletions
diff --git a/chip/lm4/task.c b/chip/lm4/task.c
index e400457e30..2e0821e80f 100644
--- a/chip/lm4/task.c
+++ b/chip/lm4/task.c
@@ -293,6 +293,52 @@ static void __nvic_init_irqs(void)
}
+void mutex_lock(struct mutex *mtx)
+{
+ uint32_t value;
+ uint32_t id = 1 << task_get_current();
+
+ ASSERT(id != TASK_ID_INVALID);
+ atomic_or(&mtx->waiters, id);
+
+ do {
+ /* try to get the lock (set 1 into the lock field) */
+ __asm__ __volatile__(" ldrex %0, [%1]\n"
+ " teq %0, #0\n"
+ " it eq\n"
+ " strexeq %0, %2, [%1]\n"
+ : "=&r" (value)
+ : "r" (&mtx->lock), "r" (1) : "cc");
+ if (value) {
+ /* contention on the mutex */
+ task_wait_msg(0);
+ }
+ } while (value);
+
+ atomic_clear(&mtx->waiters, id);
+}
+
+void mutex_unlock(struct mutex *mtx)
+{
+ uint32_t waiters;
+ task_ *tsk = __get_current();
+
+ __asm__ __volatile__(" ldr %0, [%2]\n"
+ " str %3, [%1]\n"
+ : "=&r" (waiters)
+ : "r" (&mtx->lock), "r" (&mtx->waiters), "r" (0)
+ : "cc");
+ while (waiters) {
+ task_id_t id = 31 - __builtin_clz(waiters);
+ /* somebody is waiting on the mutex */
+ task_send_msg(id, TASK_ID_MUTEX, 0);
+ waiters &= ~(1 << id);
+ }
+ /* Ensure no event is remaining from mutex wake-up */
+ atomic_clear(&tsk->events, 1 << TASK_ID_MUTEX);
+}
+
+
#ifdef CONFIG_DEBUG
/* store the task names for easier debugging */
diff --git a/include/task.h b/include/task.h
index 7e1d001f11..5cf3336841 100644
--- a/include/task.h
+++ b/include/task.h
@@ -81,6 +81,21 @@ void task_disable_irq(int irq);
/* Software-triggers an interrupt. */
void task_trigger_irq(int irq);
+struct mutex {
+ uint32_t lock;
+ uint32_t waiters;
+};
+
+/**
+ * try to lock the mutex mtx
+ * and de-schedule the task if it is already locked by another task.
+ *
+ * Should not be used in interrupt context !
+ */
+void mutex_lock(struct mutex *mtx);
+
+/* Release a mutex previously locked by the same task. */
+void mutex_unlock(struct mutex *mtx);
struct irq_priority {
uint8_t irq;
diff --git a/include/task_id.h b/include/task_id.h
index 8b6e14721f..a2fb17ca7a 100644
--- a/include/task_id.h
+++ b/include/task_id.h
@@ -32,6 +32,7 @@ enum {
/* Number of tasks */
TASK_ID_COUNT,
/* Special task identifiers */
+ TASK_ID_MUTEX = 0x1e, /* signal mutex unlocking */
TASK_ID_TIMER = 0x1f, /* message from an expired timer */
TASK_ID_CURRENT = 0xfe, /* the currently running task */
TASK_ID_INVALID = 0xff /* unable to find the task */