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