1#include "sync/tests/test_internal.h"
2
3#define MUTEX_REPORT_PROBLEMS() \
4 test_info("Mutex tests are encountering problems and will be skipped"); \
5 return TEST_SKIP(TEST_SKIP_NONE);
6
7#define MUTEX_MANY_WAITER_MAX 64
8#define MUTEX_MANY_WAITER_LOOP_COUNT 500
9
10static struct mutex many_mtx = MUTEX_INIT;
11static _Atomic uint32_t many_waiter_done = 0;
12
13static void many_worker(void *) {
14 for (int i = 0; i < MUTEX_MANY_WAITER_LOOP_COUNT; i++) {
15 mutex_lock(&many_mtx);
16 scheduler_yield();
17 mutex_unlock(&many_mtx);
18 }
19
20 atomic_fetch_sub(&many_waiter_done, 1);
21}
22
23TEST_DECLARE_INTEGRATION(mutex, many_waiters, TEST_INTENSITY(2, 10, 32)) {
24 size_t num_waiters = ctx->intensity_val ? ctx->intensity_val : 10;
25 if (num_waiters > MUTEX_MANY_WAITER_MAX)
26 num_waiters = MUTEX_MANY_WAITER_MAX;
27
28 atomic_store(&many_waiter_done, (uint32_t) num_waiters);
29 struct thread *workers[MUTEX_MANY_WAITER_MAX];
30
31 for (size_t i = 0; i < num_waiters; i++) {
32 struct thread *t = thread_create(name: "mw", entry_point: many_worker, NULL);
33 TEST_ASSERT_NONNULL(t);
34
35 thread_pin(t);
36 thread_set_joinable(t);
37 thread_enqueue(t);
38 workers[i] = t;
39 }
40
41 for (size_t i = 0; i < num_waiters; i++)
42 thread_join(t: workers[i]);
43
44 TEST_ASSERT_EQ(atomic_load(&many_waiter_done), 0);
45
46 return TEST_SUCCESS;
47}
48
49#define CHAOS_THREAD_MAX 64
50#define CHAOS_LOOPS 500
51
52static struct mutex chaos_mtx = MUTEX_INIT;
53static _Atomic uint32_t chaos_left = 0;
54
55static void chaos(void *) {
56 for (int i = 0; i < CHAOS_LOOPS; i++) {
57 mutex_lock(&chaos_mtx);
58
59 for (volatile size_t j = 0; j < (prng_next() & 0x1F); j++)
60 cpu_relax();
61
62 mutex_unlock(&chaos_mtx);
63
64 if (prng_next() & 1)
65 scheduler_yield();
66 }
67
68 atomic_fetch_sub(&chaos_left, 1);
69}
70
71volatile struct thread *main_thread = NULL;
72struct thread *other_threads[CHAOS_THREAD_MAX] = {0};
73
74TEST_DECLARE_INTEGRATION(mutex, chaos, TEST_INTENSITY(20, 50, 100)) {
75 size_t num_threads = ctx->intensity_val ? ctx->intensity_val : 24;
76 if (num_threads > CHAOS_THREAD_MAX)
77 num_threads = CHAOS_THREAD_MAX;
78
79 atomic_store(&chaos_left, (uint32_t) num_threads);
80 main_thread = thread_get_current();
81 for (size_t i = 0; i < num_threads; i++) {
82 other_threads[i] = thread_spawn_joinable(name: "ch", entry: chaos, NULL);
83 TEST_ASSERT_NONNULL(other_threads[i]);
84 }
85
86 for (size_t i = 0; i < num_threads; i++)
87 thread_join(t: other_threads[i]);
88
89 TEST_ASSERT_EQ(atomic_load(&chaos_left), 0);
90
91 return TEST_SUCCESS;
92}
93