/* * Copyright (c) 2023, Meta * * SPDX-License-Identifier: Apache-2.0 */ #include "thrd.h" #include #include #include #include static thrd_t thr; static uintptr_t param; ZTEST(libc_thrd, test_thrd_sleep) { int64_t end; int64_t start; struct timespec duration = {0}; struct timespec remaining; const uint16_t delay_ms[] = {0, 100, 200, 400}; zassert_not_equal(0, thrd_sleep(NULL, NULL)); zassert_ok(thrd_sleep(&duration, NULL)); zassert_ok(thrd_sleep(&duration, &duration)); for (int i = 0; i < ARRAY_SIZE(delay_ms); ++i) { duration = (struct timespec){.tv_nsec = delay_ms[i] * NSEC_PER_MSEC}; remaining = (struct timespec){.tv_sec = 4242, .tv_nsec = 4242}; printk("sleeping %d ms\n", delay_ms[i]); start = k_uptime_get(); zassert_ok(thrd_sleep(&duration, &remaining)); end = k_uptime_get(); zassert_equal(remaining.tv_sec, 0); zassert_equal(remaining.tv_nsec, 0); zassert_true(end - start >= delay_ms[i]); } } static int thrd_create_join_fn(void *arg) { uintptr_t *x = (uintptr_t *)arg; if (x != NULL) { *x = BIOS_FOOD; } return FORTY_TWO; } ZTEST(libc_thrd, test_thrd_create_join) { int res = 0; thrd_start_t fun = thrd_create_join_fn; param = 0; if (false) { /* pthread_create() is not hardened for degenerate cases like this */ zassert_equal(thrd_error, thrd_create(NULL, NULL, NULL)); zassert_equal(thrd_error, thrd_create(NULL, NULL, ¶m)); zassert_equal(thrd_error, thrd_create(NULL, fun, NULL)); zassert_equal(thrd_error, thrd_create(NULL, fun, ¶m)); zassert_equal(thrd_error, thrd_create(&thr, NULL, NULL)); zassert_equal(thrd_error, thrd_create(&thr, NULL, ¶m)); } zassert_equal(thrd_success, thrd_create(&thr, fun, NULL)); zassert_equal(thrd_success, thrd_join(thr, NULL)); zassert_equal(thrd_success, thrd_create(&thr, fun, ¶m)); zassert_equal(thrd_success, thrd_join(thr, &res)); zassert_equal(BIOS_FOOD, param, "expected: %d actual: %d", BIOS_FOOD, param); zassert_equal(FORTY_TWO, res); } static int thrd_exit_fn(void *arg) { uintptr_t *x = (uintptr_t *)arg; *x = BIOS_FOOD; thrd_exit(SEVENTY_THREE); return FORTY_TWO; CODE_UNREACHABLE; } ZTEST(libc_thrd, test_thrd_exit) { int res = 0; param = 0; zassert_equal(thrd_success, thrd_create(&thr, thrd_exit_fn, ¶m)); zassert_equal(thrd_success, thrd_join(thr, &res)); zassert_equal(BIOS_FOOD, param); zassert_equal(SEVENTY_THREE, res); } ZTEST(libc_thrd, test_thrd_yield) { thrd_yield(); } static thrd_t child; static thrd_t parent; static int thrd_current_equal_fn(void *arg) { ARG_UNUSED(arg); zassert_equal(thrd_current(), child); zassert_not_equal(child, parent); zassert_true(thrd_equal(thrd_current(), child)); zassert_false(thrd_equal(child, parent)); return 0; } ZTEST(libc_thrd, test_thrd_current_equal) { parent = thrd_current(); zassert_equal(thrd_success, thrd_create(&child, thrd_current_equal_fn, NULL)); zassert_equal(thrd_success, thrd_join(child, NULL)); } static bool detached_thread_is_probably_done; static int thrd_detach_fn(void *arg) { ARG_UNUSED(arg); detached_thread_is_probably_done = true; return SEVENTY_THREE; } ZTEST(libc_thrd, test_thrd_detach) { zassert_equal(thrd_success, thrd_create(&thr, thrd_detach_fn, NULL)); zassert_equal(thrd_success, thrd_detach(thr)); zassert_equal(thrd_error, thrd_join(thr, NULL)); do { k_msleep(100); } while (!detached_thread_is_probably_done); zassert_equal(thrd_error, thrd_join(thr, NULL)); } ZTEST(libc_thrd, test_thrd_reuse) { for (int i = 0; i < FORTY_TWO; ++i) { zassert_equal(thrd_success, thrd_create(&thr, thrd_create_join_fn, NULL)); zassert_equal(thrd_success, thrd_join(thr, NULL)); } } ZTEST_SUITE(libc_thrd, NULL, NULL, NULL, NULL, NULL);