blob: ce59c26e8d663776348c0d9c3181987d98914255 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_
#define ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_
#include <sched.h>
#include <threads.h>
#include <zircon/syscalls.h>
#include <unittest/unittest.h>
template <typename Mutex, typename Condition>
class GenericConditionTest {
public:
static bool condition_test() {
BEGIN_TEST;
Context ctx;
thrd_t thread1, thread2, thread3;
thrd_create(&thread1, cond_thread, &ctx);
thrd_create(&thread2, cond_thread, &ctx);
thrd_create(&thread3, cond_thread, &ctx);
// Wait for all the threads to report that they've started.
while (true) {
ctx.mutex.lock();
int threads = ctx.threads_started;
ctx.mutex.unlock();
if (threads == 3) {
break;
}
sched_yield();
}
ctx.cond.broadcast();
// Wait for all the threads to report that they were woken.
while (true) {
ctx.mutex.lock();
int threads = ctx.threads_woke_first_barrier;
ctx.mutex.unlock();
if (threads == 3) {
break;
}
sched_yield();
}
for (int iteration = 0; iteration < 3; iteration++) {
ctx.cond.signal();
// Wait for one thread to report that it was woken.
while (true) {
ctx.mutex.lock();
int threads = ctx.threads_waked;
ctx.mutex.unlock();
if (threads == iteration + 1) {
break;
}
sched_yield();
}
}
thrd_join(thread1, nullptr);
thrd_join(thread2, nullptr);
thrd_join(thread3, nullptr);
END_TEST;
}
static bool condition_timeout_test() {
BEGIN_TEST;
Condition cond;
Mutex mutex;
mutex.lock();
zx_status_t result = cond.timedwait(&mutex, ZX_MSEC(1));
mutex.unlock();
EXPECT_EQ(result, ZX_ERR_TIMED_OUT, "Lock should have timeout");
END_TEST;
}
private:
struct Context {
Mutex mutex;
Condition cond;
int threads_waked = 0;
int threads_started = 0;
int threads_woke_first_barrier = 0;
};
static int cond_thread(void* arg) {
auto* ctx = static_cast<Context*>(arg);
ctx->mutex.lock();
ctx->threads_started++;
ctx->cond.wait(&ctx->mutex);
ctx->threads_woke_first_barrier++;
ctx->cond.wait(&ctx->mutex);
ctx->threads_waked++;
ctx->mutex.unlock();
return 0;
}
};
#endif // ZIRCON_SYSTEM_UTEST_CORE_CONDITION_GENERIC_CONDITION_GENERIC_H_