1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <errno.h>
10 #include <zephyr/sys/errno_private.h>
11 
12 /**
13  * @brief Test the thread context
14  *
15  * @defgroup kernel_threadcontext_tests Thread Context Tests
16  *
17  * @ingroup all_tests
18  *
19  * @{
20  * @}
21  */
22 #define N_THREADS 2
23 #define STACK_SIZE (384 + CONFIG_TEST_EXTRA_STACK_SIZE)
24 
25 static K_THREAD_STACK_ARRAY_DEFINE(stacks, N_THREADS, STACK_SIZE);
26 static struct k_thread threads[N_THREADS];
27 
28 K_THREAD_STACK_DEFINE(eno_stack, STACK_SIZE);
29 struct k_thread eno_thread;
30 
31 static int errno_values[N_THREADS + 1] = {
32 	0xbabef00d,
33 	0xdeadbeef,
34 	0xabad1dea,
35 };
36 
37 struct result {
38 	void *q;
39 	int pass;
40 };
41 
42 struct result result[N_THREADS];
43 
44 struct k_fifo fifo;
45 
errno_thread(void * _n,void * _my_errno,void * _unused)46 static void errno_thread(void *_n, void *_my_errno, void *_unused)
47 {
48 	int n = POINTER_TO_INT(_n);
49 	int my_errno = POINTER_TO_INT(_my_errno);
50 
51 	errno = my_errno;
52 
53 	k_msleep(30 - (n * 10));
54 	if (errno == my_errno) {
55 		result[n].pass = TC_PASS;
56 	}
57 
58 	zassert_equal(errno, my_errno);
59 
60 	k_fifo_put(&fifo, &result[n]);
61 }
62 
63 /**
64  * @brief Verify thread context
65  *
66  * @ingroup kernel_threadcontext_tests
67  *
68  * @details Check whether variable value per-thread are saved during
69  *	context switch
70  */
ZTEST(common_errno,test_thread_context)71 ZTEST(common_errno, test_thread_context)
72 {
73 	int rv = TC_PASS, test_errno;
74 
75 	k_fifo_init(&fifo);
76 
77 	errno = errno_values[N_THREADS];
78 	test_errno = errno;
79 
80 	for (int ii = 0; ii < N_THREADS; ii++) {
81 		result[ii].pass = TC_FAIL;
82 	}
83 
84 	/**TESTPOINT: thread- threads stacks are separate */
85 	for (int ii = 0; ii < N_THREADS; ii++) {
86 		k_thread_create(&threads[ii], stacks[ii], STACK_SIZE,
87 				errno_thread, INT_TO_POINTER(ii),
88 				INT_TO_POINTER(errno_values[ii]), NULL,
89 				K_PRIO_PREEMPT(ii + 5), 0, K_NO_WAIT);
90 	}
91 
92 	for (int ii = 0; ii < N_THREADS; ii++) {
93 		struct result *p = k_fifo_get(&fifo, K_MSEC(100));
94 
95 		if (!p || (p->pass != TC_PASS)) {
96 			rv = TC_FAIL;
97 		}
98 	}
99 
100 	zassert_equal(errno, test_errno);
101 
102 	if (errno != errno_values[N_THREADS]) {
103 		rv = TC_FAIL;
104 	}
105 
106 	/* Make sure all the test thread end. */
107 	for (int ii = 0; ii < N_THREADS; ii++) {
108 		k_thread_join(&threads[ii], K_FOREVER);
109 	}
110 
111 	if (rv != TC_PASS) {
112 		ztest_test_fail();
113 	}
114 }
115 
116 
117 #define ERROR_ANY 0xfc
118 
thread_entry_user(void * p1,void * p2,void * p3)119 void thread_entry_user(void *p1, void *p2, void *p3)
120 {
121 #ifdef CONFIG_NATIVE_LIBC
122 	/* The errno when using the host C library will be handled by it, so we skip it.
123 	 */
124 	ztest_test_skip();
125 #else
126 	int got_errno;
127 
128 	/* assign the error number to C standard errno */
129 	errno = ERROR_ANY;
130 
131 	/* got errno zephyr stored */
132 	got_errno = *(z_errno());
133 
134 	zassert_equal(errno, got_errno, "errno is not corresponding.");
135 #endif
136 }
137 
138 /**
139  * @brief Verify errno works well
140  *
141  * @details Check whether a C standard errno can be stored successfully,
142  *  no matter it is using tls or not.
143  *
144  * @ingroup kernel_threadcontext_tests
145  */
ZTEST_USER(common_errno,test_errno)146 ZTEST_USER(common_errno, test_errno)
147 {
148 	k_tid_t tid;
149 	uint32_t perm = K_INHERIT_PERMS;
150 
151 	if (k_is_user_context()) {
152 		perm = perm | K_USER;
153 	}
154 
155 	tid = k_thread_create(&eno_thread, eno_stack, STACK_SIZE,
156 				thread_entry_user, NULL, NULL, NULL,
157 				K_PRIO_PREEMPT(1), perm,
158 				K_NO_WAIT);
159 
160 	k_thread_join(tid, K_FOREVER);
161 }
162 
163 extern void *common_setup(void);
164 
165 ZTEST_SUITE(common_errno, NULL, common_setup, NULL, NULL, NULL);
166