Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions sys/include/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,10 @@
#define VFS_H

#include <stdint.h>
/* The stdatomic.h in GCC gives compilation errors with C++
* see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
*/
#ifdef __cplusplus
#include <atomic>
/* Make atomic_int available without namespace specifier */
using std::atomic_int;
#include "c11_atomics_compat.hpp"
#else
#include <stdatomic.h> /* for atomic_int */
#include <stdatomic.h>
#endif
#include <sys/stat.h> /* for struct stat */
#include <sys/types.h> /* for off_t etc. */
Expand Down
12 changes: 12 additions & 0 deletions sys/include/xtimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "msg.h"
#endif /* MODULE_CORE_MSG */
#include "mutex.h"
#include "rmutex.h"
#include "kernel_types.h"

#ifdef MODULE_ZTIMER_XTIMER_COMPAT
Expand Down Expand Up @@ -413,6 +414,17 @@ static inline bool xtimer_less64(xtimer_ticks64_t a, xtimer_ticks64_t b);
*/
int xtimer_mutex_lock_timeout(mutex_t *mutex, uint64_t us);

/**
* @brief lock a rmutex but with timeout
*
* @param[in] rmutex rmutex 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_rmutex_lock_timeout(rmutex_t *rmutex, uint64_t us);

#if defined(MODULE_CORE_THREAD_FLAGS) || defined(DOXYGEN)
/**
* @brief Set timeout thread flag after @p timeout
Expand Down
18 changes: 18 additions & 0 deletions sys/xtimer/xtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "xtimer.h"
#include "mutex.h"
#include "rmutex.h"
#include "thread.h"
#include "irq.h"
#include "div.h"
Expand Down Expand Up @@ -270,6 +271,23 @@ int xtimer_mutex_lock_timeout(mutex_t *mutex, uint64_t timeout)
return -mt.dequeued;
}

int xtimer_rmutex_lock_timeout(rmutex_t *rmutex, uint64_t timeout)
{
if (rmutex_trylock(rmutex) == 1) {
return 0;
}
if (xtimer_mutex_lock_timeout(&rmutex->mutex, timeout) < 0) {
return -1;
}
/* the mutex is locked, update the owner */
/* ensure that owner is written atomically, since others need a consistent value */
atomic_store_explicit(&rmutex->owner, thread_getpid(), memory_order_relaxed);
/* increase the refcount */
rmutex->refcount++;

return 0;
}

#ifdef MODULE_CORE_THREAD_FLAGS
static void _set_timeout_flag_callback(void* arg)
{
Expand Down
2 changes: 2 additions & 0 deletions tests/rmutex/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
include ../Makefile.tests_common

USEMODULE += xtimer

include $(RIOTBASE)/Makefile.include
60 changes: 58 additions & 2 deletions tests/rmutex/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "rmutex.h"
#include "thread.h"
#include "xtimer.h"

#define THREAD_NUMOF (5U)

Expand All @@ -31,6 +32,8 @@ static char stacks[THREAD_NUMOF][THREAD_STACKSIZE_MAIN];

static const char prios[THREAD_NUMOF] = {THREAD_PRIORITY_MAIN - 1, 4, 5, 2, 4};
static const char depth[THREAD_NUMOF] = {5, 3, 3, 4, 5};
static const unsigned timeouts[THREAD_NUMOF] = { 100 * US_PER_MS, 200 * US_PER_MS, 300 * US_PER_MS,
400 * US_PER_MS, 500 * US_PER_MS};

static rmutex_t testlock;

Expand All @@ -45,8 +48,9 @@ static void lock_recursive(char n, char depth)
printf("T%i (prio %i, depth %i): locked rmutex now\n",
(int)t->pid, (int)t->priority, (int)n);

if (n + 1 < depth)
if (n + 1 < depth) {
lock_recursive(n + 1, depth);
}

thread_yield();

Expand All @@ -65,6 +69,42 @@ static void *lockme(void *arg)
return NULL;
}

static void lock_recursive_timeout(char n, uint32_t us)
{
volatile thread_t *t = sched_active_thread;

printf("T%i (prio %i, depth %i, timeout %" PRIu32 "): trying to lock rmutex now\n",
(int)t->pid, (int)t->priority, (int)n, us);
if (xtimer_rmutex_lock_timeout(&testlock, us) < 0) {
printf("T%i (prio %i, depth %i): timeout\n",
(int)t->pid, (int)t->priority, (int)n);
return;
}

printf("T%i (prio %i, depth %i): locked rmutex now\n",
(int)t->pid, (int)t->priority, (int)n);

if (n + 1 < 3) {
lock_recursive_timeout(n + 1, us);
}

thread_yield();

rmutex_unlock(&testlock);

printf("T%i (prio %i, depth %i): unlocked rmutex\n",
(int)t->pid, (int)t->priority, (int)n);
}

static void *lockme_timeout(void *arg)
{
intptr_t timeout = (intptr_t)arg;

lock_recursive_timeout(0, timeout);

return NULL;
}

int main(void)
{
puts("Recursive Mutex test");
Expand All @@ -77,14 +117,30 @@ int main(void)
/* create threads */
for (unsigned i = 0; i < THREAD_NUMOF; i++) {
thread_create(stacks[i], sizeof(stacks[i]), prios[i], 0,
lockme, (void*)(intptr_t)depth[i], "t");
lockme, (void*)(intptr_t)depth[i], "t");
}
/* allow threads to lock the mutex */
printf("main: unlocking recursive mutex\n");

rmutex_unlock(&testlock);
/* test 1 END */

/* xtimer_rmutex_lock_timeout() test */
/* lock mutex, so that spawned threads have to wait */
rmutex_lock(&testlock);
/* create threads */
for (unsigned i = 0; i < THREAD_NUMOF; i++) {
thread_create(stacks[i], sizeof(stacks[i]), prios[i], 0,
lockme_timeout, (void*)(intptr_t)timeouts[i], "t");
}
/* wait to have some thread timeouts */
puts("main: waiting 250ms");
xtimer_usleep(250 * US_PER_MS);
/* allow threads to lock the mutex */
printf("main: unlocking recursive mutex\n");

rmutex_unlock(&testlock);

puts("\nTest END, check the order of priorities above.");

return 0;
Expand Down
26 changes: 26 additions & 0 deletions tests/rmutex/tests/01-run.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
7: 5
}

timeouts = {
3: 100000,
4: 200000,
5: 300000,
6: 400000,
7: 500000
}


def thread_prio_sort(x):
return thread_prio.get(x)*1000 + x
Expand All @@ -44,6 +52,24 @@ def testfunc(child):
child.expect_exact("T{} (prio {}, depth {}): locked rmutex now"
.format(T, thread_prio[T], depth))

# xtimer_rmutex_lock_timeout() test
for k in thread_prio.keys():
child.expect_exact("T{} (prio {}, depth 0, timeout {}): trying to lock rmutex now"
.format(k, thread_prio[k], timeouts[k]))
child.expect_exact("main: waiting 250ms")
for k in range(3, 4):
child.expect_exact("T{} (prio {}, depth 0): timeout"
.format(k, thread_prio[k]))
child.expect_exact
child.expect_exact("main: unlocking recursive mutex")
pri_sorted = sorted({k: thread_prio[k] for k in (5, 6, 7)}, key=thread_prio_sort)
for T in pri_sorted:
for depth in range(3):
child.expect_exact("T{} (prio {}, depth {}): locked rmutex now"
.format(T, thread_prio[T], depth))

child.expect_exact("Test END, check the order of priorities above.")


if __name__ == "__main__":
sys.exit(run(testfunc))