mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:52:44 +01:00
sys/xtimer: clean up xtimer_mutex_lock_timeout
Use `mutex_lock_cancelable()` and `mutex_cancel()` to implement `xtimer_mutex_lock_timeout()`.
This commit is contained in:
parent
1feacd1b88
commit
4f36d21957
@ -40,24 +40,6 @@
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* @brief: struct for mutex lock with timeout
|
||||
* xtimer_mutex_lock_timeout() uses it to give information to the timer callback function
|
||||
*/
|
||||
typedef struct {
|
||||
mutex_t *mutex;
|
||||
thread_t *thread;
|
||||
/*
|
||||
* @brief: one means the thread was removed from the mutex thread waiting list
|
||||
* by _mutex_timeout()
|
||||
*/
|
||||
volatile uint8_t dequeued;
|
||||
/*
|
||||
* @brief: mutex_lock() should block because _mutex_timeout() did not shoot
|
||||
*/
|
||||
volatile uint8_t blocking;
|
||||
} mutex_thread_t;
|
||||
|
||||
static void _callback_unlock_mutex(void* arg)
|
||||
{
|
||||
mutex_t *mutex = (mutex_t *) arg;
|
||||
@ -210,106 +192,30 @@ void xtimer_now_timex(timex_t *out)
|
||||
out->microseconds = now - (out->seconds * US_PER_SEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* The value pointed to by unlocked will be set to 1 if the thread was removed from the waiting queue otherwise 0.
|
||||
*/
|
||||
static void _mutex_remove_thread_from_waiting_queue(mutex_t *mutex, thread_t *thread, volatile uint8_t *unlocked)
|
||||
{
|
||||
unsigned irqstate = irq_disable();
|
||||
assert(mutex != NULL && thread != NULL);
|
||||
|
||||
if (mutex->queue.next != MUTEX_LOCKED && mutex->queue.next != NULL) {
|
||||
list_node_t *node = list_remove(&mutex->queue, (list_node_t *)&thread->rq_entry);
|
||||
/* if thread was removed from the list */
|
||||
if (node != NULL) {
|
||||
if (mutex->queue.next == NULL) {
|
||||
mutex->queue.next = MUTEX_LOCKED;
|
||||
}
|
||||
*unlocked = 1;
|
||||
|
||||
sched_set_status(thread, STATUS_PENDING);
|
||||
irq_restore(irqstate);
|
||||
sched_switch(thread->priority);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*unlocked = 0;
|
||||
irq_restore(irqstate);
|
||||
}
|
||||
|
||||
static void _mutex_timeout(void *arg)
|
||||
{
|
||||
/* interrupts are disabled because xtimer can spin
|
||||
* if xtimer_set spins the callback is executed
|
||||
* in the thread context
|
||||
*
|
||||
* If the xtimer spin is fixed in the future
|
||||
* interups disable/restore can be removed
|
||||
*/
|
||||
unsigned int irqstate = irq_disable();
|
||||
|
||||
mutex_thread_t *mt = arg;
|
||||
mt->blocking = 0;
|
||||
_mutex_remove_thread_from_waiting_queue(mt->mutex, mt->thread, &mt->dequeued);
|
||||
irq_restore(irqstate);
|
||||
}
|
||||
|
||||
static int _mutex_lock_internal(mutex_t *mutex, volatile uint8_t *blocking)
|
||||
{
|
||||
unsigned irqstate = irq_disable();
|
||||
|
||||
DEBUG("PID[%" PRIkernel_pid "]: Mutex in use.\n", thread_getpid());
|
||||
|
||||
if (mutex->queue.next == NULL) {
|
||||
/* mutex is unlocked. */
|
||||
mutex->queue.next = MUTEX_LOCKED;
|
||||
DEBUG("PID[%" PRIkernel_pid "]: mutex_wait early out.\n",
|
||||
thread_getpid());
|
||||
irq_restore(irqstate);
|
||||
return 1;
|
||||
}
|
||||
else if (*blocking) {
|
||||
thread_t *me = thread_get_active();
|
||||
DEBUG("PID[%" PRIkernel_pid "]: Adding node to mutex queue: prio: %"
|
||||
PRIu32 "\n", thread_getpid(), (uint32_t)me->priority);
|
||||
sched_set_status(me, STATUS_MUTEX_BLOCKED);
|
||||
if (mutex->queue.next == MUTEX_LOCKED) {
|
||||
mutex->queue.next = (list_node_t *)&me->rq_entry;
|
||||
mutex->queue.next->next = NULL;
|
||||
}
|
||||
else {
|
||||
thread_add_to_list(&mutex->queue, me);
|
||||
}
|
||||
irq_restore(irqstate);
|
||||
thread_yield_higher();
|
||||
/* We were woken up by scheduler. Waker removed us from queue.
|
||||
* We have the mutex now. */
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
irq_restore(irqstate);
|
||||
return 0;
|
||||
}
|
||||
mutex_cancel(arg);
|
||||
}
|
||||
|
||||
int xtimer_mutex_lock_timeout(mutex_t *mutex, uint64_t timeout)
|
||||
{
|
||||
xtimer_t t;
|
||||
mutex_thread_t mt = {
|
||||
mutex, thread_get_active(), .dequeued = 0, .blocking = 1
|
||||
};
|
||||
|
||||
if (timeout != 0) {
|
||||
t.callback = _mutex_timeout;
|
||||
t.arg = &mt;
|
||||
xtimer_set64(&t, timeout);
|
||||
if (mutex_trylock(mutex)) {
|
||||
return 0;
|
||||
}
|
||||
int ret = _mutex_lock_internal(mutex, &mt.blocking);
|
||||
if (ret == 0) {
|
||||
|
||||
if (timeout == 0) {
|
||||
return - 1;
|
||||
}
|
||||
|
||||
mutex_cancel_t mc = mutex_cancel_init(mutex);
|
||||
xtimer_t t = { .callback = _mutex_timeout, .arg = &mc };
|
||||
|
||||
xtimer_set64(&t, timeout);
|
||||
if (mutex_lock_cancelable(&mc)) {
|
||||
return -1;
|
||||
}
|
||||
xtimer_remove(&t);
|
||||
return -mt.dequeued;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xtimer_rmutex_lock_timeout(rmutex_t *rmutex, uint64_t timeout)
|
||||
|
Loading…
Reference in New Issue
Block a user