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, ¶m),
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, ¶m), 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, ¶m), 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, ¶m), ESRCH,
452 "get schedparam with NULL error");
453 zassert_equal(pthread_setschedparam(PTHREAD_INVALID, policy, ¶m), 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, ¶m),
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