blob: e9d69d43fbaadb84c49a16e5e3d3e1f2cae82388 [file] [log] [blame]
// Copyright 2016 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.
#include <zircon/syscalls.h>
#include <runtime/mutex.h>
#include <unittest/unittest.h>
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
static zxr_mutex_t mutex = ZXR_MUTEX_INIT;
static void xlog(const char* str) {
uint64_t now = zx_time_get(ZX_CLOCK_MONOTONIC);
unittest_printf("[%08" PRIu64 ".%08" PRIu64 "]: %s",
now / 1000000000, now % 1000000000, str);
}
static int mutex_thread_1(void* arg) {
xlog("thread 1 started\n");
for (int times = 0; times < 300; times++) {
zxr_mutex_lock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(1)));
zxr_mutex_unlock(&mutex);
}
xlog("thread 1 done\n");
return 0;
}
static int mutex_thread_2(void* arg) {
xlog("thread 2 started\n");
for (int times = 0; times < 150; times++) {
zxr_mutex_lock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(2)));
zxr_mutex_unlock(&mutex);
}
xlog("thread 2 done\n");
return 0;
}
static int mutex_thread_3(void* arg) {
xlog("thread 3 started\n");
for (int times = 0; times < 100; times++) {
zxr_mutex_lock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(3)));
zxr_mutex_unlock(&mutex);
}
xlog("thread 3 done\n");
return 0;
}
static bool got_lock_1 = false;
static bool got_lock_2 = false;
static bool got_lock_3 = false;
static int mutex_try_thread_1(void* arg) {
xlog("thread 1 started\n");
for (int times = 0; times < 300 || !got_lock_1; times++) {
zx_status_t status = zxr_mutex_trylock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(1)));
if (status == ZX_OK) {
got_lock_1 = true;
zxr_mutex_unlock(&mutex);
}
}
xlog("thread 1 done\n");
return 0;
}
static int mutex_try_thread_2(void* arg) {
xlog("thread 2 started\n");
for (int times = 0; times < 150 || !got_lock_2; times++) {
zx_status_t status = zxr_mutex_trylock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(2)));
if (status == ZX_OK) {
got_lock_2 = true;
zxr_mutex_unlock(&mutex);
}
}
xlog("thread 2 done\n");
return 0;
}
static int mutex_try_thread_3(void* arg) {
xlog("thread 3 started\n");
for (int times = 0; times < 100 || !got_lock_3; times++) {
zx_status_t status = zxr_mutex_trylock(&mutex);
zx_nanosleep(zx_deadline_after(ZX_USEC(3)));
if (status == ZX_OK) {
got_lock_3 = true;
zxr_mutex_unlock(&mutex);
}
}
xlog("thread 3 done\n");
return 0;
}
static bool test_initializer(void) {
BEGIN_TEST;
// Let's not accidentally break .bss'd mutexes
static zxr_mutex_t static_mutex;
zxr_mutex_t mutex = ZXR_MUTEX_INIT;
int status = memcmp(&static_mutex, &mutex, sizeof(zxr_mutex_t));
EXPECT_EQ(status, 0, "zxr_mutex's initializer is not all zeroes");
END_TEST;
}
static bool test_mutexes(void) {
BEGIN_TEST;
thrd_t thread1, thread2, thread3;
thrd_create_with_name(&thread1, mutex_thread_1, NULL, "thread 1");
thrd_create_with_name(&thread2, mutex_thread_2, NULL, "thread 2");
thrd_create_with_name(&thread3, mutex_thread_3, NULL, "thread 3");
thrd_join(thread1, NULL);
thrd_join(thread2, NULL);
thrd_join(thread3, NULL);
END_TEST;
}
static bool test_try_mutexes(void) {
BEGIN_TEST;
thrd_t thread1, thread2, thread3;
thrd_create_with_name(&thread1, mutex_try_thread_1, NULL, "thread 1");
thrd_create_with_name(&thread2, mutex_try_thread_2, NULL, "thread 2");
thrd_create_with_name(&thread3, mutex_try_thread_3, NULL, "thread 3");
thrd_join(thread1, NULL);
thrd_join(thread2, NULL);
thrd_join(thread3, NULL);
EXPECT_TRUE(got_lock_1, "failed to get lock 1");
EXPECT_TRUE(got_lock_2, "failed to get lock 2");
EXPECT_TRUE(got_lock_3, "failed to get lock 3");
END_TEST;
}
BEGIN_TEST_CASE(zxr_mutex_tests)
RUN_TEST(test_initializer)
RUN_TEST(test_mutexes)
RUN_TEST(test_try_mutexes)
END_TEST_CASE(zxr_mutex_tests)
#ifndef BUILD_COMBINED_TESTS
int main(int argc, char** argv) {
return unittest_run_all_tests(argc, argv) ? 0 : -1;
}
#endif