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, &param));
66 		zassert_equal(thrd_error, thrd_create(NULL, fun, NULL));
67 		zassert_equal(thrd_error, thrd_create(NULL, fun, &param));
68 		zassert_equal(thrd_error, thrd_create(&thr, NULL, NULL));
69 		zassert_equal(thrd_error, thrd_create(&thr, NULL, &param));
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, &param));
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, &param));
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