diff --git a/core/include/mutex.h b/core/include/mutex.h index 2c4d3425f8..ecb817a479 100644 --- a/core/include/mutex.h +++ b/core/include/mutex.h @@ -68,6 +68,13 @@ int mutex_lock(struct mutex_t *mutex); */ void mutex_unlock(struct mutex_t *mutex); +/** + * @brief Unlocks the mutex and sends the current thread to sleep + * + * @param mutex Mutex-Object to unlock. + */ +void mutex_unlock_and_sleep(struct mutex_t *mutex); + #define MUTEX_YIELD 1 #define MUTEX_INISR 2 diff --git a/core/mutex.c b/core/mutex.c index 664b864df4..297c8513a5 100644 --- a/core/mutex.c +++ b/core/mutex.c @@ -117,3 +117,25 @@ void mutex_unlock(struct mutex_t *mutex) restoreIRQ(irqstate); } + +void mutex_unlock_and_sleep(struct mutex_t *mutex) +{ + DEBUG("%s: unlocking mutex. val: %u pid: %u, and take a nap\n", active_thread->name, mutex->val, thread_pid); + int irqstate = disableIRQ(); + + if (mutex->val != 0) { + if (mutex->queue.next) { + queue_node_t *next = queue_remove_head(&(mutex->queue)); + tcb_t *process = (tcb_t*) next->data; + DEBUG("%s: waking up waiter.\n", process->name); + sched_set_status(process, STATUS_PENDING); + } + else { + mutex->val = 0; + } + } + DEBUG("%s: going to sleep.\n", active_thread->name); + sched_set_status((tcb_t*) active_thread, STATUS_SLEEPING); + restoreIRQ(irqstate); + thread_yield(); +}