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