diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 31c85c5e35..8f12e5043e 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -32,6 +32,7 @@ #include #include "timex.h" #include "msg.h" +#include "mutex.h" #include "board.h" #include "periph_conf.h" @@ -425,6 +426,19 @@ static inline bool xtimer_less(xtimer_ticks32_t a, xtimer_ticks32_t b); */ static inline bool xtimer_less64(xtimer_ticks64_t a, xtimer_ticks64_t b); +/** + * @brief lock a mutex but with timeout + * + * @note this requires core_thread_flags to be enabled + * + * @param[in] mutex mutex to lock + * @param[in] us timeout in microseconds relative + * + * @return 0, when returned after mutex was locked + * @return -1, when the timeout occcured + */ +int xtimer_mutex_lock_timeout(mutex_t *mutex, uint64_t us); + /** * @brief xtimer backoff value * diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index f55da0b58b..475a769d27 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -26,12 +26,19 @@ #include "thread.h" #include "irq.h" #include "div.h" +#include "list.h" #include "timex.h" #define ENABLE_DEBUG 0 #include "debug.h" +typedef struct { + mutex_t *mutex; + thread_t *thread; + int timeout; +} mutex_thread_t; + static void _callback_unlock_mutex(void* arg) { mutex_t *mutex = (mutex_t *) arg; @@ -220,3 +227,29 @@ int _xtimer_msg_receive_timeout(msg_t *msg, uint32_t timeout_ticks) _xtimer_set_msg(&t, timeout_ticks, &tmsg, sched_active_pid); return _msg_wait(msg, &tmsg, &t); } + +static void _mutex_timeout(void *arg) +{ + mutex_thread_t *mt = (mutex_thread_t *)arg; + + mt->timeout = 1; + sched_set_status(mt->thread, STATUS_PENDING); + list_remove(&mt->mutex->queue, (list_node_t *)&mt->thread->rq_entry); + thread_yield_higher(); +} + +int xtimer_mutex_lock_timeout(mutex_t *mutex, uint64_t timeout) +{ + xtimer_t t; + mutex_thread_t mt = { mutex, (thread_t *)sched_active_thread, 0 }; + + if (timeout != 0) { + t.callback = _mutex_timeout; + t.arg = (void *)((mutex_thread_t *)&mt); + _xtimer_set64(&t, timeout, timeout >> 32); + } + + mutex_lock(mutex); + xtimer_remove(&t); + return -mt.timeout; +}