1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <pthread.h>
10 #include <semaphore.h>
11 #include <zephyr/sys/util.h>
12 
13 #ifndef min
14 #define min(a, b) ((a) < (b)) ? (a) : (b)
15 #endif
16 
17 #define N_THR_E 3
18 #define N_THR_T 4
19 #define BOUNCES 64
20 #define STACKS (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
21 #define THREAD_PRIORITY 3
22 #define ONE_SECOND 1
23 
24 /* Macros to test invalid states */
25 #define PTHREAD_CANCEL_INVALID -1
26 #define SCHED_INVALID -1
27 #define PRIO_INVALID -1
28 #define PTHREAD_INVALID -1
29 
30 K_THREAD_STACK_ARRAY_DEFINE(stack_e, N_THR_E, STACKS);
31 K_THREAD_STACK_ARRAY_DEFINE(stack_t, N_THR_T, STACKS);
32 K_THREAD_STACK_ARRAY_DEFINE(stack_1, 1, 32);
33 
34 void *thread_top_exec(void *p1);
35 void *thread_top_term(void *p1);
36 
37 PTHREAD_MUTEX_DEFINE(lock);
38 
39 PTHREAD_COND_DEFINE(cvar0);
40 
41 PTHREAD_COND_DEFINE(cvar1);
42 
43 static pthread_barrier_t barrier;
44 
45 sem_t main_sem;
46 
47 static int bounce_failed;
48 static int bounce_done[N_THR_E];
49 
50 static int curr_bounce_thread;
51 
52 static int barrier_failed;
53 static int barrier_done[N_THR_E];
54 static int barrier_return[N_THR_E];
55 
56 /* First phase bounces execution between two threads using a condition
57  * variable, continuously testing that no other thread is mucking with
58  * the protected state.  This ends with all threads going back to
59  * sleep on the condition variable and being woken by main() for the
60  * second phase.
61  *
62  * Second phase simply lines up all the threads on a barrier, verifies
63  * that none run until the last one enters, and that all run after the
64  * exit.
65  *
66  * Test success is signaled to main() using a traditional semaphore.
67  */
68 
thread_top_exec(void * p1)69 void *thread_top_exec(void *p1)
70 {
71 	int i, j, id = (int) POINTER_TO_INT(p1);
72 	int policy;
73 	struct sched_param schedparam;
74 
75 	pthread_getschedparam(pthread_self(), &policy, &schedparam);
76 	printk("Thread %d starting with scheduling policy %d & priority %d\n",
77 		 id, policy, schedparam.sched_priority);
78 	/* Try a double-lock here to exercise the failing case of
79 	 * trylock.  We don't support RECURSIVE locks, so this is
80 	 * guaranteed to fail.
81 	 */
82 	pthread_mutex_lock(&lock);
83 
84 	if (!pthread_mutex_trylock(&lock)) {
85 		printk("pthread_mutex_trylock inexplicably succeeded\n");
86 		bounce_failed = 1;
87 	}
88 
89 	pthread_mutex_unlock(&lock);
90 
91 	for (i = 0; i < BOUNCES; i++) {
92 
93 		pthread_mutex_lock(&lock);
94 
95 		/* Wait for the current owner to signal us, unless we
96 		 * are the very first thread, in which case we need to
97 		 * wait a bit to be sure the other threads get
98 		 * scheduled and wait on cvar0.
99 		 */
100 		if (!(id == 0 && i == 0)) {
101 			zassert_equal(0, pthread_cond_wait(&cvar0, &lock), "");
102 		} else {
103 			pthread_mutex_unlock(&lock);
104 			usleep(USEC_PER_MSEC * 500U);
105 			pthread_mutex_lock(&lock);
106 		}
107 
108 		/* Claim ownership, then try really hard to give someone
109 		 * else a shot at hitting this if they are racing.
110 		 */
111 		curr_bounce_thread = id;
112 		for (j = 0; j < 1000; j++) {
113 			if (curr_bounce_thread != id) {
114 				printk("Racing bounce threads\n");
115 				bounce_failed = 1;
116 				sem_post(&main_sem);
117 				pthread_mutex_unlock(&lock);
118 				return NULL;
119 			}
120 			sched_yield();
121 		}
122 
123 		/* Next one's turn, go back to the top and wait.  */
124 		pthread_cond_signal(&cvar0);
125 		pthread_mutex_unlock(&lock);
126 	}
127 
128 	/* Signal we are complete to main(), then let it wake us up.  Note
129 	 * that we are using the same mutex with both cvar0 and cvar1,
130 	 * which is non-standard but kosher per POSIX (and it works fine
131 	 * in our implementation
132 	 */
133 	pthread_mutex_lock(&lock);
134 	bounce_done[id] = 1;
135 	sem_post(&main_sem);
136 	pthread_cond_wait(&cvar1, &lock);
137 	pthread_mutex_unlock(&lock);
138 
139 	/* Now just wait on the barrier.  Make sure no one else finished
140 	 * before we wait on it, then signal that we're done
141 	 */
142 	for (i = 0; i < N_THR_E; i++) {
143 		if (barrier_done[i]) {
144 			printk("Barrier exited early\n");
145 			barrier_failed = 1;
146 			sem_post(&main_sem);
147 		}
148 	}
149 	barrier_return[id] = pthread_barrier_wait(&barrier);
150 	barrier_done[id] = 1;
151 	sem_post(&main_sem);
152 	pthread_exit(p1);
153 
154 	return NULL;
155 }
156 
bounce_test_done(void)157 int bounce_test_done(void)
158 {
159 	int i;
160 
161 	if (bounce_failed) {
162 		return 1;
163 	}
164 
165 	for (i = 0; i < N_THR_E; i++) {
166 		if (!bounce_done[i]) {
167 			return 0;
168 		}
169 	}
170 
171 	return 1;
172 }
173 
barrier_test_done(void)174 int barrier_test_done(void)
175 {
176 	int i;
177 
178 	if (barrier_failed) {
179 		return 1;
180 	}
181 
182 	for (i = 0; i < N_THR_E; i++) {
183 		if (!barrier_done[i]) {
184 			return 0;
185 		}
186 	}
187 
188 	return 1;
189 }
190 
thread_top_term(void * p1)191 void *thread_top_term(void *p1)
192 {
193 	pthread_t self;
194 	int oldstate, policy, ret;
195 	int id = POINTER_TO_INT(p1);
196 	struct sched_param param, getschedparam;
197 
198 	param.sched_priority = N_THR_T - id;
199 
200 	self = pthread_self();
201 
202 	/* Change priority of thread */
203 	zassert_false(pthread_setschedparam(self, SCHED_RR, &param),
204 		      "Unable to set thread priority!");
205 
206 	zassert_false(pthread_getschedparam(self, &policy, &getschedparam),
207 			"Unable to get thread priority!");
208 
209 	printk("Thread %d starting with a priority of %d\n",
210 			id,
211 			getschedparam.sched_priority);
212 
213 	if (id % 2) {
214 		ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
215 		zassert_false(ret, "Unable to set cancel state!");
216 	}
217 
218 	if (id >= 2) {
219 		ret = pthread_detach(self);
220 		if (id == 2) {
221 			zassert_equal(ret, EINVAL, "re-detached thread!");
222 		}
223 	}
224 
225 	printk("Cancelling thread %d\n", id);
226 	pthread_cancel(self);
227 	printk("Thread %d could not be cancelled\n", id);
228 	sleep(ONE_SECOND);
229 	pthread_exit(p1);
230 	return NULL;
231 }
232 
ZTEST(posix_apis,test_posix_pthread_execution)233 ZTEST(posix_apis, test_posix_pthread_execution)
234 {
235 	int i, ret, min_prio, max_prio;
236 	int dstate, policy;
237 	pthread_attr_t attr[N_THR_E] = {};
238 	struct sched_param schedparam, getschedparam;
239 	pthread_t newthread[N_THR_E];
240 	int schedpolicy = SCHED_FIFO;
241 	void *retval, *stackaddr;
242 	size_t stacksize;
243 	int serial_threads = 0;
244 	static const char thr_name[] = "thread name";
245 	char thr_name_buf[CONFIG_THREAD_MAX_NAME_LEN];
246 
247 	/*
248 	 * initialize barriers the standard way after deprecating
249 	 * PTHREAD_BARRIER_DEFINE().
250 	 */
251 	zassert_ok(pthread_barrier_init(&barrier, NULL, N_THR_E));
252 
253 	sem_init(&main_sem, 0, 1);
254 	schedparam.sched_priority = CONFIG_NUM_COOP_PRIORITIES - 1;
255 	min_prio = sched_get_priority_min(schedpolicy);
256 	max_prio = sched_get_priority_max(schedpolicy);
257 
258 	ret = (min_prio < 0 || max_prio < 0 ||
259 			schedparam.sched_priority < min_prio ||
260 			schedparam.sched_priority > max_prio);
261 
262 	/* TESTPOINT: Check if scheduling priority is valid */
263 	zassert_false(ret,
264 			"Scheduling priority outside valid priority range");
265 
266 	/* TESTPOINTS: Try setting attributes before init */
267 	ret = pthread_attr_setschedparam(&attr[0], &schedparam);
268 	zassert_equal(ret, EINVAL, "uninitialized attr set!");
269 
270 	ret = pthread_attr_setdetachstate(&attr[0], PTHREAD_CREATE_JOINABLE);
271 	zassert_equal(ret, EINVAL, "uninitialized attr set!");
272 
273 	ret = pthread_attr_setschedpolicy(&attr[0], schedpolicy);
274 	zassert_equal(ret, EINVAL, "uninitialized attr set!");
275 
276 	/* TESTPOINT: Try setting attribute with empty stack */
277 	ret = pthread_attr_setstack(&attr[0], 0, STACKS);
278 	zassert_equal(ret, EACCES, "empty stack set!");
279 
280 	/* TESTPOINTS: Try getting attributes before init */
281 	ret = pthread_attr_getschedparam(&attr[0], &getschedparam);
282 	zassert_equal(ret, EINVAL, "uninitialized attr retrieved!");
283 
284 	ret = pthread_attr_getdetachstate(&attr[0], &dstate);
285 	zassert_equal(ret, EINVAL, "uninitialized attr retrieved!");
286 
287 	ret = pthread_attr_getschedpolicy(&attr[0], &policy);
288 	zassert_equal(ret, EINVAL, "uninitialized attr retrieved!");
289 
290 	ret = pthread_attr_getstack(&attr[0], &stackaddr, &stacksize);
291 	zassert_equal(ret, EINVAL, "uninitialized attr retrieved!");
292 
293 	ret = pthread_attr_getstacksize(&attr[0], &stacksize);
294 	zassert_equal(ret, EINVAL, "uninitialized attr retrieved!");
295 
296 	/* TESTPOINT: Try destroying attr before init */
297 	ret = pthread_attr_destroy(&attr[0]);
298 	zassert_equal(ret, EINVAL, "uninitialized attr destroyed!");
299 
300 	/* TESTPOINT: Try getting name of NULL thread (aka uninitialized
301 	 * thread var).
302 	 */
303 	ret = pthread_getname_np(PTHREAD_INVALID, thr_name_buf, sizeof(thr_name_buf));
304 	zassert_equal(ret, ESRCH, "uninitialized getname!");
305 
306 	/* TESTPOINT: Try setting name of NULL thread (aka uninitialized
307 	 * thread var).
308 	 */
309 	ret = pthread_setname_np(PTHREAD_INVALID, thr_name);
310 	zassert_equal(ret, ESRCH, "uninitialized setname!");
311 
312 	/* TESTPOINT: Try creating thread before attr init */
313 	ret = pthread_create(&newthread[0], &attr[0],
314 				thread_top_exec, NULL);
315 	zassert_equal(ret, EINVAL, "thread created before attr init!");
316 
317 	for (i = 0; i < N_THR_E; i++) {
318 		ret = pthread_attr_init(&attr[i]);
319 		if (ret != 0) {
320 			zassert_false(pthread_attr_destroy(&attr[i]),
321 				      "Unable to destroy pthread object attrib");
322 			zassert_false(pthread_attr_init(&attr[i]),
323 				      "Unable to create pthread object attrib");
324 		}
325 
326 		/* TESTPOINTS: Retrieve set stack attributes and compare */
327 		pthread_attr_setstack(&attr[i], &stack_e[i][0], STACKS);
328 		stackaddr = NULL;
329 		pthread_attr_getstack(&attr[i], &stackaddr, &stacksize);
330 		zassert_equal_ptr(&stack_e[i][0], stackaddr,
331 				  "stack attribute addresses do not match!");
332 		zassert_equal(STACKS, stacksize, "stack sizes do not match!");
333 
334 		pthread_attr_getstacksize(&attr[i], &stacksize);
335 		zassert_equal(STACKS, stacksize, "stack sizes do not match!");
336 
337 		pthread_attr_setschedpolicy(&attr[i], schedpolicy);
338 		pthread_attr_getschedpolicy(&attr[i], &policy);
339 		zassert_equal(schedpolicy, policy,
340 				"scheduling policies do not match!");
341 
342 		pthread_attr_setschedparam(&attr[i], &schedparam);
343 		pthread_attr_getschedparam(&attr[i], &getschedparam);
344 		zassert_equal(schedparam.sched_priority,
345 			      getschedparam.sched_priority,
346 			      "scheduling priorities do not match!");
347 
348 		ret = pthread_create(&newthread[i], &attr[i], thread_top_exec,
349 				INT_TO_POINTER(i));
350 
351 		/* TESTPOINT: Check if thread is created successfully */
352 		zassert_false(ret, "Number of threads exceed max limit");
353 	}
354 
355 	/* TESTPOINT: Try getting thread name with no buffer */
356 	ret = pthread_getname_np(newthread[0], NULL, sizeof(thr_name_buf));
357 	zassert_equal(ret, EINVAL, "uninitialized getname!");
358 
359 	/* TESTPOINT: Try setting thread name with no buffer */
360 	ret = pthread_setname_np(newthread[0], NULL);
361 	zassert_equal(ret, EINVAL, "uninitialized setname!");
362 
363 	/* TESTPOINT: Try setting thread name */
364 	ret = pthread_setname_np(newthread[0], thr_name);
365 	zassert_false(ret, "Set thread name failed!");
366 
367 	/* TESTPOINT: Try getting thread name */
368 	ret = pthread_getname_np(newthread[0], thr_name_buf,
369 				 sizeof(thr_name_buf));
370 	zassert_false(ret, "Get thread name failed!");
371 
372 	/* TESTPOINT: Thread names match */
373 	ret = strncmp(thr_name, thr_name_buf, min(strlen(thr_name),
374 						  strlen(thr_name_buf)));
375 	zassert_false(ret, "Thread names don't match!");
376 
377 	while (!bounce_test_done()) {
378 		sem_wait(&main_sem);
379 	}
380 
381 	/* TESTPOINT: Check if bounce test passes */
382 	zassert_false(bounce_failed, "Bounce test failed");
383 
384 	printk("Bounce test OK\n");
385 
386 	/* Wake up the worker threads */
387 	pthread_mutex_lock(&lock);
388 	pthread_cond_broadcast(&cvar1);
389 	pthread_mutex_unlock(&lock);
390 
391 	while (!barrier_test_done()) {
392 		sem_wait(&main_sem);
393 	}
394 
395 	/* TESTPOINT: Check if barrier test passes */
396 	zassert_false(barrier_failed, "Barrier test failed");
397 
398 	for (i = 0; i < N_THR_E; i++) {
399 		pthread_join(newthread[i], &retval);
400 	}
401 
402 	for (i = 0; i < N_THR_E; i++) {
403 		if (barrier_return[i] == PTHREAD_BARRIER_SERIAL_THREAD) {
404 			++serial_threads;
405 		}
406 	}
407 
408 	/* TESTPOINT: Check only one PTHREAD_BARRIER_SERIAL_THREAD returned. */
409 	zassert_true(serial_threads == 1, "Bungled barrier return value(s)");
410 
411 	printk("Barrier test OK\n");
412 }
413 
ZTEST(posix_apis,test_posix_pthread_error_condition)414 ZTEST(posix_apis, test_posix_pthread_error_condition)
415 {
416 	pthread_attr_t attr;
417 	struct sched_param param;
418 	void *stackaddr;
419 	size_t stacksize;
420 	int policy, detach;
421 	static pthread_once_t key;
422 
423 	/* TESTPOINT: invoke pthread APIs with NULL */
424 	zassert_equal(pthread_attr_destroy(NULL), EINVAL,
425 		      "pthread destroy NULL error");
426 	zassert_equal(pthread_attr_getschedparam(NULL, &param), EINVAL,
427 		      "get scheduling param error");
428 	zassert_equal(pthread_attr_getstack(NULL, &stackaddr, &stacksize),
429 		      EINVAL, "get stack attributes error");
430 	zassert_equal(pthread_attr_getstacksize(NULL, &stacksize),
431 		      EINVAL, "get stack size error");
432 	zassert_equal(pthread_attr_setschedpolicy(NULL, 2),
433 		      EINVAL, "set scheduling policy error");
434 	zassert_equal(pthread_attr_getschedpolicy(NULL, &policy),
435 		      EINVAL, "get scheduling policy error");
436 	zassert_equal(pthread_attr_setdetachstate(NULL, 0),
437 		      EINVAL, "pthread set detach state with NULL error");
438 	zassert_equal(pthread_attr_getdetachstate(NULL, &detach),
439 		      EINVAL, "get detach state error");
440 	zassert_equal(pthread_detach(PTHREAD_INVALID), ESRCH, "detach with NULL error");
441 	zassert_equal(pthread_attr_init(NULL), ENOMEM,
442 		      "init with NULL error");
443 	zassert_equal(pthread_attr_setschedparam(NULL, &param), EINVAL,
444 		      "set sched param with NULL error");
445 	zassert_equal(pthread_cancel(PTHREAD_INVALID), ESRCH,
446 		      "cancel NULL error");
447 	zassert_equal(pthread_join(PTHREAD_INVALID, NULL), ESRCH,
448 		      "join with NULL has error");
449 	zassert_false(pthread_once(&key, NULL),
450 		      "pthread dynamic package initialization error");
451 	zassert_equal(pthread_getschedparam(PTHREAD_INVALID, &policy, &param), ESRCH,
452 		      "get schedparam with NULL error");
453 	zassert_equal(pthread_setschedparam(PTHREAD_INVALID, policy, &param), ESRCH,
454 		      "set schedparam with NULL error");
455 
456 	attr = (pthread_attr_t){0};
457 	zassert_equal(pthread_attr_getdetachstate(&attr, &detach),
458 		      EINVAL, "get detach state error");
459 
460 	/* Initialise thread attribute to ensure won't be return with init error */
461 	zassert_false(pthread_attr_init(&attr),
462 		      "Unable to create pthread object attr");
463 	zassert_false(pthread_attr_setschedpolicy(&attr, SCHED_FIFO),
464 		      "set scheduling policy error");
465 	zassert_false(pthread_attr_setschedpolicy(&attr, SCHED_RR), "set scheduling policy error");
466 	zassert_false(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE),
467 		      "set detach state error");
468 	zassert_false(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED),
469 		      "set detach state error");
470 	zassert_equal(pthread_attr_setdetachstate(&attr, 3),
471 		      EINVAL, "set detach state error");
472 	zassert_false(pthread_attr_getdetachstate(&attr, &detach),
473 		      "get detach state error");
474 }
475 
ZTEST(posix_apis,test_posix_pthread_termination)476 ZTEST(posix_apis, test_posix_pthread_termination)
477 {
478 	int32_t i, ret;
479 	int oldstate, policy;
480 	pthread_attr_t attr[N_THR_T];
481 	struct sched_param schedparam;
482 	pthread_t newthread[N_THR_T];
483 	void *retval;
484 
485 	/* Creating 4 threads with lowest application priority */
486 	for (i = 0; i < N_THR_T; i++) {
487 		ret = pthread_attr_init(&attr[i]);
488 		if (ret != 0) {
489 			zassert_false(pthread_attr_destroy(&attr[i]),
490 				      "Unable to destroy pthread object attrib");
491 			zassert_false(pthread_attr_init(&attr[i]),
492 				      "Unable to create pthread object attrib");
493 		}
494 
495 		if (i == 2) {
496 			pthread_attr_setdetachstate(&attr[i],
497 						    PTHREAD_CREATE_DETACHED);
498 		}
499 
500 		schedparam.sched_priority = 2;
501 		pthread_attr_setschedparam(&attr[i], &schedparam);
502 		pthread_attr_setstack(&attr[i], &stack_t[i][0], STACKS);
503 		ret = pthread_create(&newthread[i], &attr[i], thread_top_term,
504 				     INT_TO_POINTER(i));
505 
506 		zassert_false(ret, "Not enough space to create new thread");
507 	}
508 
509 	/* TESTPOINT: Try setting invalid cancel state to current thread */
510 	ret = pthread_setcancelstate(PTHREAD_CANCEL_INVALID, &oldstate);
511 	zassert_equal(ret, EINVAL, "invalid cancel state set!");
512 
513 	/* TESTPOINT: Try setting invalid policy */
514 	ret = pthread_setschedparam(newthread[0], SCHED_INVALID, &schedparam);
515 	zassert_equal(ret, EINVAL, "invalid policy set!");
516 
517 	/* TESTPOINT: Try setting invalid priority */
518 	schedparam.sched_priority = PRIO_INVALID;
519 	ret = pthread_setschedparam(newthread[0], SCHED_RR, &schedparam);
520 	zassert_equal(ret, EINVAL, "invalid priority set!");
521 
522 	for (i = 0; i < N_THR_T; i++) {
523 		pthread_join(newthread[i], &retval);
524 	}
525 
526 	/* TESTPOINT: Test for deadlock */
527 	ret = pthread_join(pthread_self(), &retval);
528 	zassert_equal(ret, EDEADLK, "thread joined with self inexplicably!");
529 
530 	/* TESTPOINT: Try canceling a terminated thread */
531 	ret = pthread_cancel(newthread[N_THR_T/2]);
532 	zassert_equal(ret, ESRCH, "cancelled a terminated thread!");
533 
534 	/* TESTPOINT: Try getting scheduling info from terminated thread */
535 	ret = pthread_getschedparam(newthread[N_THR_T/2], &policy, &schedparam);
536 	zassert_equal(ret, ESRCH, "got attr from terminated thread!");
537 }
538 
ZTEST(posix_apis,test_posix_thread_attr_stacksize)539 ZTEST(posix_apis, test_posix_thread_attr_stacksize)
540 {
541 	size_t act_size;
542 	pthread_attr_t attr;
543 	const size_t exp_size = 0xB105F00D;
544 
545 	/* TESTPOINT: specify a custom stack size via pthread_attr_t */
546 	zassert_equal(0, pthread_attr_init(&attr), "pthread_attr_init() failed");
547 
548 	if (PTHREAD_STACK_MIN > 0) {
549 		zassert_equal(EINVAL, pthread_attr_setstacksize(&attr, 0),
550 			      "pthread_attr_setstacksize() did not fail");
551 	}
552 
553 	zassert_equal(0, pthread_attr_setstacksize(&attr, exp_size),
554 		      "pthread_attr_setstacksize() failed");
555 	zassert_equal(0, pthread_attr_getstacksize(&attr, &act_size),
556 		      "pthread_attr_getstacksize() failed");
557 	zassert_equal(exp_size, act_size, "wrong size: act: %zu exp: %zu",
558 		exp_size, act_size);
559 }
560 
create_thread1(void * p1)561 static void *create_thread1(void *p1)
562 {
563 	/* do nothing */
564 	return NULL;
565 }
566 
ZTEST(posix_apis,test_posix_pthread_create_negative)567 ZTEST(posix_apis, test_posix_pthread_create_negative)
568 {
569 	int ret;
570 	pthread_t pthread1;
571 	pthread_attr_t attr1;
572 
573 	/* create pthread without attr initialized */
574 	ret = pthread_create(&pthread1, NULL, create_thread1, (void *)1);
575 	zassert_equal(ret, EINVAL, "create thread with NULL successful");
576 
577 	/* initialized attr without set stack to create thread */
578 	ret = pthread_attr_init(&attr1);
579 	zassert_false(ret, "attr1 initialized failed");
580 
581 	attr1 = (pthread_attr_t){0};
582 	ret = pthread_create(&pthread1, &attr1, create_thread1, (void *)1);
583 	zassert_equal(ret, EINVAL, "create successful with NULL attr");
584 
585 	/* set stack size 0 to create thread */
586 	pthread_attr_setstack(&attr1, &stack_1, 0);
587 	ret = pthread_create(&pthread1, &attr1, create_thread1, (void *)1);
588 	zassert_equal(ret, EINVAL, "create thread with 0 size");
589 }
590 
ZTEST(posix_apis,test_pthread_descriptor_leak)591 ZTEST(posix_apis, test_pthread_descriptor_leak)
592 {
593 	pthread_t pthread1;
594 	pthread_attr_t attr;
595 
596 	zassert_ok(pthread_attr_init(&attr));
597 	zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS));
598 
599 	/* If we are leaking descriptors, then this loop will never complete */
600 	for (size_t i = 0; i < CONFIG_MAX_PTHREAD_COUNT * 2; ++i) {
601 		zassert_ok(pthread_create(&pthread1, &attr, create_thread1, NULL),
602 			   "unable to create thread %zu", i);
603 		/*
604 		 * k_msleep() should not be necessary, but it is added as a workaround
605 		 * for #56163 and #58116, which identified race conditions on some
606 		 * platforms.
607 		 */
608 		k_msleep(100);
609 		zassert_ok(pthread_join(pthread1, NULL), "unable to join thread %zu", i);
610 	}
611 }
612 
ZTEST(posix_apis,test_sched_policy)613 ZTEST(posix_apis, test_sched_policy)
614 {
615 	/*
616 	 * TODO:
617 	 * 1. assert that _POSIX_PRIORITY_SCHEDULING is defined
618 	 * 2. if _POSIX_SPORADIC_SERVER or _POSIX_THREAD_SPORADIC_SERVER are defined,
619 	 *    also check SCHED_SPORADIC
620 	 * 3. SCHED_OTHER is mandatory (but may be equivalent to SCHED_FIFO or SCHED_RR,
621 	 *    and is implementation defined)
622 	 */
623 
624 	int pmin;
625 	int pmax;
626 	pthread_t th;
627 	pthread_attr_t attr;
628 	struct sched_param param;
629 	static const int policies[] = {
630 		SCHED_FIFO,
631 		SCHED_RR,
632 		SCHED_OTHER,
633 		SCHED_INVALID,
634 	};
635 	static const char *const policy_names[] = {
636 		"SCHED_FIFO",
637 		"SCHED_RR",
638 		"SCHED_OTHER",
639 		"SCHED_INVALID",
640 	};
641 	static const bool policy_enabled[] = {
642 		IS_ENABLED(CONFIG_COOP_ENABLED),
643 		IS_ENABLED(CONFIG_PREEMPT_ENABLED),
644 		IS_ENABLED(CONFIG_PREEMPT_ENABLED),
645 		false,
646 	};
647 	static int nprio[] = {
648 		CONFIG_NUM_COOP_PRIORITIES,
649 		CONFIG_NUM_PREEMPT_PRIORITIES,
650 		CONFIG_NUM_PREEMPT_PRIORITIES,
651 		42,
652 	};
653 	const char *const prios[] = {"pmin", "pmax"};
654 
655 	BUILD_ASSERT(!(SCHED_INVALID == SCHED_FIFO || SCHED_INVALID == SCHED_RR ||
656 		       SCHED_INVALID == SCHED_OTHER),
657 		     "SCHED_INVALID is itself invalid");
658 
659 	for (int policy = 0; policy < ARRAY_SIZE(policies); ++policy) {
660 		if (!policy_enabled[policy]) {
661 			/* test degenerate cases */
662 			errno = 0;
663 			zassert_equal(-1, sched_get_priority_min(policies[policy]),
664 				      "expected sched_get_priority_min(%s) to fail",
665 				      policy_names[policy]);
666 			zassert_equal(EINVAL, errno, "sched_get_priority_min(%s) did not set errno",
667 				      policy_names[policy]);
668 
669 			errno = 0;
670 			zassert_equal(-1, sched_get_priority_max(policies[policy]),
671 				      "expected sched_get_priority_max(%s) to fail",
672 				      policy_names[policy]);
673 			zassert_equal(EINVAL, errno, "sched_get_priority_max(%s) did not set errno",
674 				      policy_names[policy]);
675 			continue;
676 		}
677 
678 		/* get pmin and pmax for policies[policy] */
679 		for (int i = 0; i < 2; ++i) {
680 			errno = 0;
681 			if (i == 0) {
682 				pmin = sched_get_priority_min(policies[policy]);
683 				param.sched_priority = pmin;
684 			} else {
685 				pmax = sched_get_priority_max(policies[policy]);
686 				param.sched_priority = pmax;
687 			}
688 
689 			zassert_not_equal(-1, param.sched_priority,
690 					  "sched_get_priority_%s(%s) failed: %d",
691 					  i == 0 ? "min" : "max", policy_names[policy], errno);
692 			zassert_ok(errno, "sched_get_priority_%s(%s) set errno to %s",
693 				   i == 0 ? "min" : "max", policy_names[policy], errno);
694 		}
695 
696 		/*
697 		 * IEEE 1003.1-2008 Section 2.8.4
698 		 * conforming implementations should provide a range of at least 32 priorities
699 		 *
700 		 * Note: we relax this requirement
701 		 */
702 		zassert_true(pmax > pmin, "pmax (%d) <= pmin (%d)", pmax, pmin,
703 			     "%s min/max inconsistency: pmin: %d pmax: %d", policy_names[policy],
704 			     pmin, pmax);
705 
706 		/*
707 		 * Getting into the weeds a bit (i.e. whitebox testing), Zephyr
708 		 * cooperative threads use [-CONFIG_NUM_COOP_PRIORITIES,-1] and
709 		 * preemptive threads use [0, CONFIG_NUM_PREEMPT_PRIORITIES - 1],
710 		 * where the more negative thread has the higher priority. Since we
711 		 * cannot map those directly (a return value of -1 indicates error),
712 		 * we simply map those to the positive space.
713 		 */
714 		zassert_equal(pmin, 0, "unexpected pmin for %s", policy_names[policy]);
715 		zassert_equal(pmax, nprio[policy] - 1, "unexpected pmax for %s",
716 			      policy_names[policy]); /* test happy paths */
717 
718 		for (int i = 0; i < 2; ++i) {
719 			/* create threads with min and max priority levels */
720 			zassert_ok(pthread_attr_init(&attr),
721 				   "pthread_attr_init() failed for %s (%d) of %s", prios[i],
722 				   param.sched_priority, policy_names[policy]);
723 
724 			zassert_ok(pthread_attr_setschedpolicy(&attr, policies[policy]),
725 				   "pthread_attr_setschedpolicy() failed for %s (%d) of %s",
726 				   prios[i], param.sched_priority, policy_names[policy]);
727 
728 			zassert_ok(pthread_attr_setschedparam(&attr, &param),
729 				   "pthread_attr_setschedparam() failed for %s (%d) of %s",
730 				   prios[i], param.sched_priority, policy_names[policy]);
731 
732 			zassert_ok(pthread_attr_setstack(&attr, &stack_e[0][0], STACKS),
733 				   "pthread_attr_setstack() failed for %s (%d) of %s", prios[i],
734 				   param.sched_priority, policy_names[policy]);
735 
736 			zassert_ok(pthread_create(&th, &attr, create_thread1, NULL),
737 				   "pthread_create() failed for %s (%d) of %s", prios[i],
738 				   param.sched_priority, policy_names[policy]);
739 
740 			zassert_ok(pthread_join(th, NULL),
741 				   "pthread_join() failed for %s (%d) of %s", prios[i],
742 				   param.sched_priority, policy_names[policy]);
743 		}
744 	}
745 }
746