diff options
-rw-r--r-- | chip/lm4/task.c | 46 | ||||
-rw-r--r-- | include/task.h | 15 | ||||
-rw-r--r-- | include/task_id.h | 1 |
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 */ |