1 /*
2 * Copyright (c) 2023, Meta
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "thrd.h"
8
9 #include <stdint.h>
10 #include <threads.h>
11
12 #include <zephyr/sys_clock.h>
13 #include <zephyr/ztest.h>
14
15 static thrd_t thr;
16 static uintptr_t param;
17
ZTEST(libc_thrd,test_thrd_sleep)18 ZTEST(libc_thrd, test_thrd_sleep)
19 {
20 int64_t end;
21 int64_t start;
22 struct timespec duration = {0};
23 struct timespec remaining;
24 const uint16_t delay_ms[] = {0, 100, 200, 400};
25
26 zassert_not_equal(0, thrd_sleep(NULL, NULL));
27 zassert_ok(thrd_sleep(&duration, NULL));
28 zassert_ok(thrd_sleep(&duration, &duration));
29
30 for (int i = 0; i < ARRAY_SIZE(delay_ms); ++i) {
31 duration = (struct timespec){.tv_nsec = delay_ms[i] * NSEC_PER_MSEC};
32 remaining = (struct timespec){.tv_sec = 4242, .tv_nsec = 4242};
33
34 printk("sleeping %d ms\n", delay_ms[i]);
35 start = k_uptime_get();
36 zassert_ok(thrd_sleep(&duration, &remaining));
37 end = k_uptime_get();
38 zassert_equal(remaining.tv_sec, 0);
39 zassert_equal(remaining.tv_nsec, 0);
40 zassert_true(end - start >= delay_ms[i]);
41 }
42 }
43
thrd_create_join_fn(void * arg)44 static int thrd_create_join_fn(void *arg)
45 {
46 uintptr_t *x = (uintptr_t *)arg;
47
48 if (x != NULL) {
49 *x = BIOS_FOOD;
50 }
51
52 return FORTY_TWO;
53 }
54
ZTEST(libc_thrd,test_thrd_create_join)55 ZTEST(libc_thrd, test_thrd_create_join)
56 {
57 int res = 0;
58 thrd_start_t fun = thrd_create_join_fn;
59
60 param = 0;
61
62 if (false) {
63 /* pthread_create() is not hardened for degenerate cases like this */
64 zassert_equal(thrd_error, thrd_create(NULL, NULL, NULL));
65 zassert_equal(thrd_error, thrd_create(NULL, NULL, ¶m));
66 zassert_equal(thrd_error, thrd_create(NULL, fun, NULL));
67 zassert_equal(thrd_error, thrd_create(NULL, fun, ¶m));
68 zassert_equal(thrd_error, thrd_create(&thr, NULL, NULL));
69 zassert_equal(thrd_error, thrd_create(&thr, NULL, ¶m));
70 }
71
72 zassert_equal(thrd_success, thrd_create(&thr, fun, NULL));
73 zassert_equal(thrd_success, thrd_join(thr, NULL));
74
75 zassert_equal(thrd_success, thrd_create(&thr, fun, ¶m));
76 zassert_equal(thrd_success, thrd_join(thr, &res));
77 zassert_equal(BIOS_FOOD, param, "expected: %d actual: %d", BIOS_FOOD, param);
78 zassert_equal(FORTY_TWO, res);
79 }
80
thrd_exit_fn(void * arg)81 static int thrd_exit_fn(void *arg)
82 {
83 uintptr_t *x = (uintptr_t *)arg;
84
85 *x = BIOS_FOOD;
86
87 thrd_exit(SEVENTY_THREE);
88
89 return FORTY_TWO;
90
91 CODE_UNREACHABLE;
92 }
93
ZTEST(libc_thrd,test_thrd_exit)94 ZTEST(libc_thrd, test_thrd_exit)
95 {
96 int res = 0;
97
98 param = 0;
99
100 zassert_equal(thrd_success, thrd_create(&thr, thrd_exit_fn, ¶m));
101 zassert_equal(thrd_success, thrd_join(thr, &res));
102 zassert_equal(BIOS_FOOD, param);
103 zassert_equal(SEVENTY_THREE, res);
104 }
105
ZTEST(libc_thrd,test_thrd_yield)106 ZTEST(libc_thrd, test_thrd_yield)
107 {
108 thrd_yield();
109 }
110
111 static thrd_t child;
112 static thrd_t parent;
113
thrd_current_equal_fn(void * arg)114 static int thrd_current_equal_fn(void *arg)
115 {
116 ARG_UNUSED(arg);
117
118 zassert_equal(thrd_current(), child);
119 zassert_not_equal(child, parent);
120
121 zassert_true(thrd_equal(thrd_current(), child));
122 zassert_false(thrd_equal(child, parent));
123
124 return 0;
125 }
126
ZTEST(libc_thrd,test_thrd_current_equal)127 ZTEST(libc_thrd, test_thrd_current_equal)
128 {
129 parent = thrd_current();
130
131 zassert_equal(thrd_success, thrd_create(&child, thrd_current_equal_fn, NULL));
132 zassert_equal(thrd_success, thrd_join(child, NULL));
133 }
134
135 static bool detached_thread_is_probably_done;
136
thrd_detach_fn(void * arg)137 static int thrd_detach_fn(void *arg)
138 {
139 ARG_UNUSED(arg);
140
141 detached_thread_is_probably_done = true;
142 return SEVENTY_THREE;
143 }
144
ZTEST(libc_thrd,test_thrd_detach)145 ZTEST(libc_thrd, test_thrd_detach)
146 {
147 zassert_equal(thrd_success, thrd_create(&thr, thrd_detach_fn, NULL));
148 zassert_equal(thrd_success, thrd_detach(thr));
149 zassert_equal(thrd_error, thrd_join(thr, NULL));
150
151 do {
152 k_msleep(100);
153 } while (!detached_thread_is_probably_done);
154
155 zassert_equal(thrd_error, thrd_join(thr, NULL));
156 }
157
ZTEST(libc_thrd,test_thrd_reuse)158 ZTEST(libc_thrd, test_thrd_reuse)
159 {
160 for (int i = 0; i < FORTY_TWO; ++i) {
161 zassert_equal(thrd_success, thrd_create(&thr, thrd_create_join_fn, NULL));
162 zassert_equal(thrd_success, thrd_join(thr, NULL));
163 }
164 }
165
166 ZTEST_SUITE(libc_thrd, NULL, NULL, NULL, NULL, NULL);
167