module thread_test; import std::thread; import std::os; const TEST_MAGNITUDE = 10; fn void own_mutex(Mutex* m) { m.lock(); m.unlock(); } fn void ensure_owner_checks() @test { Mutex m; m.init()!!; Thread[3 * TEST_MAGNITUDE] threads; foreach(&t : threads) { t.create((ThreadFn)&own_mutex, &m)!!; } foreach(&t : threads) t.join(); own_mutex(&m); } struct ArgsWrapper1 { Mutex* m; ulong* v; } fn void shared_mutex_increment(ArgsWrapper1* args) { args.m.lock(); args.v++; args.m.unlock(); } fn void shared_mutex_decrement(ArgsWrapper1* args) { args.m.lock(); args.v--; args.m.unlock(); } fn void shared_mutex() @test { Mutex m; m.init()!!; m.lock(); ulong v; ArgsWrapper1 args = { .m = &m, .v = &v }; // An even number of threads must be chosen Thread[6 * TEST_MAGNITUDE] threads; for (int i = 0; i < threads.len / 2; i++) { (&threads[i]).create((ThreadFn)&shared_mutex_increment, &args)!!; } for (int i = (threads.len / 2); i < threads.len; i++) { (&threads[i]).create((ThreadFn)&shared_mutex_decrement, &args)!!; } m.unlock(); foreach(&t : threads) t.join(); assert(v == 0); } // Recursive mutex fn void acquire_recursively(RecursiveMutex* m) { // TODO: The recursive mutex functions can not directly be called via pointer for (usz i = 0; i < 5 * TEST_MAGNITUDE; i++) { ((Mutex*)m).lock(); } for (usz i = 0; i < 5 * TEST_MAGNITUDE; i++) { ((Mutex*)m).unlock(); } } fn void test_recursive_mutex() @test { RecursiveMutex m; m.init()!!; defer m.destroy(); Thread[3 * TEST_MAGNITUDE] threads; foreach(&t : threads) { t.create((ThreadFn)&acquire_recursively, &m)!!; } foreach(&t : threads) t.join(); return acquire_recursively(&m); }