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