1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_ 6 #define ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_ 7 8 #include <sched.h> 9 #include <threads.h> 10 #include <zircon/syscalls.h> 11 12 #include <unittest/unittest.h> 13 14 template <typename Mutex, typename Condition> 15 class GenericConditionTest { 16 public: condition_test()17 static bool condition_test() { 18 BEGIN_TEST; 19 20 Context ctx; 21 22 thrd_t thread1, thread2, thread3; 23 24 thrd_create(&thread1, cond_thread, &ctx); 25 thrd_create(&thread2, cond_thread, &ctx); 26 thrd_create(&thread3, cond_thread, &ctx); 27 28 // Wait for all the threads to report that they've started. 29 while (true) { 30 ctx.mutex.lock(); 31 int threads = ctx.threads_started; 32 ctx.mutex.unlock(); 33 if (threads == 3) { 34 break; 35 } 36 sched_yield(); 37 } 38 39 ctx.cond.broadcast(); 40 41 // Wait for all the threads to report that they were woken. 42 while (true) { 43 ctx.mutex.lock(); 44 int threads = ctx.threads_woke_first_barrier; 45 ctx.mutex.unlock(); 46 if (threads == 3) { 47 break; 48 } 49 sched_yield(); 50 } 51 52 for (int iteration = 0; iteration < 3; iteration++) { 53 ctx.cond.signal(); 54 55 // Wait for one thread to report that it was woken. 56 while (true) { 57 ctx.mutex.lock(); 58 int threads = ctx.threads_waked; 59 ctx.mutex.unlock(); 60 if (threads == iteration + 1) { 61 break; 62 } 63 sched_yield(); 64 } 65 } 66 67 thrd_join(thread1, nullptr); 68 thrd_join(thread2, nullptr); 69 thrd_join(thread3, nullptr); 70 71 END_TEST; 72 } 73 condition_timeout_test()74 static bool condition_timeout_test() { 75 BEGIN_TEST; 76 77 Condition cond; 78 Mutex mutex; 79 80 mutex.lock(); 81 zx_status_t result = cond.timedwait(&mutex, ZX_MSEC(1)); 82 mutex.unlock(); 83 84 EXPECT_EQ(result, ZX_ERR_TIMED_OUT, "Lock should have timeout"); 85 86 END_TEST; 87 } 88 89 private: 90 struct Context { 91 Mutex mutex; 92 Condition cond; 93 int threads_waked = 0; 94 int threads_started = 0; 95 int threads_woke_first_barrier = 0; 96 }; 97 cond_thread(void * arg)98 static int cond_thread(void* arg) { 99 auto* ctx = static_cast<Context*>(arg); 100 101 ctx->mutex.lock(); 102 ctx->threads_started++; 103 ctx->cond.wait(&ctx->mutex); 104 ctx->threads_woke_first_barrier++; 105 ctx->cond.wait(&ctx->mutex); 106 ctx->threads_waked++; 107 ctx->mutex.unlock(); 108 return 0; 109 } 110 }; 111 112 #endif // ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_ 113