From 5387cbe26195e329e33ffd135a74cc997aaaf38d Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 24 Mar 2020 15:37:13 +0100 Subject: [PATCH 1/3] xtimer: add xtimer_rmutex_lock_timeout() Similar to xtimer_mutex_lock_timeout(), it allows to try locking a rmutex with a timeout. The rmutex test app has been updated accordingly. --- sys/include/xtimer.h | 12 ++++++++ sys/xtimer/xtimer.c | 18 +++++++++++ tests/rmutex/Makefile | 2 ++ tests/rmutex/main.c | 60 ++++++++++++++++++++++++++++++++++-- tests/rmutex/tests/01-run.py | 25 +++++++++++++++ 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index bd1e1c50a35a..d30da427c5ca 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -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 @@ -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 diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index 85762280848f..f5d6cd736e5d 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -24,6 +24,7 @@ #include "xtimer.h" #include "mutex.h" +#include "rmutex.h" #include "thread.h" #include "irq.h" #include "div.h" @@ -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, upadte 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) { diff --git a/tests/rmutex/Makefile b/tests/rmutex/Makefile index 24bb48165705..8bff23ceead2 100644 --- a/tests/rmutex/Makefile +++ b/tests/rmutex/Makefile @@ -1,3 +1,5 @@ include ../Makefile.tests_common +USEMODULE += xtimer + include $(RIOTBASE)/Makefile.include diff --git a/tests/rmutex/main.c b/tests/rmutex/main.c index 03004ca9331b..2e34590c3d2a 100644 --- a/tests/rmutex/main.c +++ b/tests/rmutex/main.c @@ -22,6 +22,7 @@ #include "rmutex.h" #include "thread.h" +#include "xtimer.h" #define THREAD_NUMOF (5U) @@ -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; @@ -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(); @@ -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"); @@ -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; diff --git a/tests/rmutex/tests/01-run.py b/tests/rmutex/tests/01-run.py index 0ca8ae3748fe..ed8687e53f77 100755 --- a/tests/rmutex/tests/01-run.py +++ b/tests/rmutex/tests/01-run.py @@ -28,6 +28,13 @@ 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 @@ -44,6 +51,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)) From a0ca39471e80dc6ba54b064a5dee46ad62938865 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Fri, 27 Mar 2020 10:13:27 +0100 Subject: [PATCH 2/3] fixup! xtimer: add xtimer_rmutex_lock_timeout() --- sys/xtimer/xtimer.c | 2 +- tests/rmutex/tests/01-run.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/xtimer/xtimer.c b/sys/xtimer/xtimer.c index f5d6cd736e5d..90be5fff14d2 100644 --- a/sys/xtimer/xtimer.c +++ b/sys/xtimer/xtimer.c @@ -279,7 +279,7 @@ int xtimer_rmutex_lock_timeout(rmutex_t *rmutex, uint64_t timeout) if (xtimer_mutex_lock_timeout(&rmutex->mutex, timeout) < 0) { return -1; } - /* the mutex is locked, upadte the owner */ + /* 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 */ diff --git a/tests/rmutex/tests/01-run.py b/tests/rmutex/tests/01-run.py index ed8687e53f77..b731b3e336d1 100755 --- a/tests/rmutex/tests/01-run.py +++ b/tests/rmutex/tests/01-run.py @@ -36,6 +36,7 @@ 7: 500000 } + def thread_prio_sort(x): return thread_prio.get(x)*1000 + x @@ -61,7 +62,7 @@ def testfunc(child): .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) + 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" From 34d3c9462baa22117b6828faa1775bf98afef7f1 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Fri, 27 Mar 2020 11:39:11 +0100 Subject: [PATCH 3/3] vfs: fix building with cpp11 atomics --- sys/include/vfs.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sys/include/vfs.h b/sys/include/vfs.h index 157b25e2e59b..216606a1da9e 100644 --- a/sys/include/vfs.h +++ b/sys/include/vfs.h @@ -54,15 +54,10 @@ #define VFS_H #include -/* The stdatomic.h in GCC gives compilation errors with C++ - * see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 - */ #ifdef __cplusplus -#include -/* Make atomic_int available without namespace specifier */ -using std::atomic_int; +#include "c11_atomics_compat.hpp" #else -#include /* for atomic_int */ +#include #endif #include /* for struct stat */ #include /* for off_t etc. */