1 /*
2 * Copyright (c) 2012-2015 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @brief test context and thread APIs
9 *
10 * @defgroup kernel_context_tests Context Tests
11 *
12 * @ingroup all_tests
13 *
14 * This module tests the following CPU and thread related routines:
15 * k_thread_create(), k_yield(), k_is_in_isr(),
16 * k_current_get(), k_cpu_idle(), k_cpu_atomic_idle(),
17 * irq_lock(), irq_unlock(),
18 * irq_offload(), irq_enable(), irq_disable(),
19 * @{
20 * @}
21 */
22
23 #include <stdlib.h>
24 #include <zephyr/ztest.h>
25 #include <zephyr/kernel_structs.h>
26 #include <zephyr/arch/cpu.h>
27 #include <zephyr/irq_offload.h>
28 #include <zephyr/sys_clock.h>
29
30 #if defined(CONFIG_SOC_POSIX)
31 /* TIMER_TICK_IRQ <soc.h> header for certain platforms */
32 #include <soc.h>
33 #endif
34
35 #define THREAD_STACKSIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
36 #define THREAD_STACKSIZE2 (384 + CONFIG_TEST_EXTRA_STACK_SIZE)
37 #define THREAD_PRIORITY 4
38
39 #define THREAD_SELF_CMD 0
40 #define EXEC_CTX_TYPE_CMD 1
41
42 #define UNKNOWN_COMMAND -1
43 #define INVALID_BEHAVIOUR -2
44
45 /*
46 * Get the timer type dependent IRQ number. If timer type
47 * is not defined in platform, generate an error
48 */
49
50 #if defined(CONFIG_APIC_TSC_DEADLINE_TIMER)
51 #define TICK_IRQ z_loapic_irq_base() /* first LVT interrupt */
52 #elif defined(CONFIG_CPU_CORTEX_M)
53 /*
54 * The Cortex-M use the SYSTICK exception for the system timer, which is
55 * not considered an IRQ by the irq_enable/Disable APIs.
56 */
57 #elif defined(CONFIG_SPARC)
58 #elif defined(CONFIG_MIPS)
59 #elif defined(CONFIG_ARCH_POSIX)
60 #if defined(CONFIG_BOARD_NATIVE_POSIX)
61 #define TICK_IRQ TIMER_TICK_IRQ
62 #else
63 /*
64 * Other POSIX arch boards will skip the irq_disable() and irq_enable() test
65 * unless TICK_IRQ is defined here for them
66 */
67 #endif /* defined(CONFIG_ARCH_POSIX) */
68 #else
69
70 extern const int32_t z_sys_timer_irq_for_test;
71 #define TICK_IRQ (z_sys_timer_irq_for_test)
72
73 #endif
74
75 /* Cortex-M1 and Nios II do have a power saving instruction, so k_cpu_idle()
76 * returns immediately
77 */
78 #if !defined(CONFIG_CPU_CORTEX_M1) && !defined(CONFIG_NIOS2)
79 #define HAS_POWERSAVE_INSTRUCTION
80 #endif
81
82
83
84 typedef struct {
85 int command; /* command to process */
86 int error; /* error value (if any) */
87 union {
88 void *data; /* pointer to data to use or return */
89 int value; /* value to be passed or returned */
90 };
91 } ISR_INFO;
92
93
94 typedef int (*disable_int_func) (int);
95 typedef void (*enable_int_func) (int);
96
97 static struct k_sem sem_thread;
98 static struct k_timer timer;
99 static struct k_sem reply_timeout;
100 struct k_fifo timeout_order_fifo;
101
102 static int thread_evidence;
103
104 static K_THREAD_STACK_DEFINE(thread_stack1, THREAD_STACKSIZE);
105 static K_THREAD_STACK_DEFINE(thread_stack2, THREAD_STACKSIZE);
106 static K_THREAD_STACK_DEFINE(thread_stack3, THREAD_STACKSIZE);
107 static struct k_thread thread_data1;
108 static struct k_thread thread_data2;
109 static struct k_thread thread_data3;
110
111 static ISR_INFO isr_info;
112
113 /**
114 * @brief Handler to perform various actions from within an ISR context
115 *
116 * This routine is the ISR handler for isr_handler_trigger(). It performs
117 * the command requested in <isr_info.command>.
118 */
isr_handler(const void * data)119 static void isr_handler(const void *data)
120 {
121 ARG_UNUSED(data);
122
123 if (k_can_yield()) {
124 isr_info.error = INVALID_BEHAVIOUR;
125 }
126
127 switch (isr_info.command) {
128 case THREAD_SELF_CMD:
129 isr_info.data = (void *)k_current_get();
130 break;
131
132 case EXEC_CTX_TYPE_CMD:
133 if (k_is_in_isr()) {
134 isr_info.value = K_ISR;
135 break;
136 }
137
138 if (_current->base.prio < 0) {
139 isr_info.value = K_COOP_THREAD;
140 break;
141 }
142
143 isr_info.value = K_PREEMPT_THREAD;
144
145 break;
146
147 default:
148 isr_info.error = UNKNOWN_COMMAND;
149 break;
150 }
151 }
152
isr_handler_trigger(void)153 static void isr_handler_trigger(void)
154 {
155 irq_offload(isr_handler, NULL);
156 }
157
158 /**
159 *
160 * @brief Initialize kernel objects
161 *
162 * This routine initializes the kernel objects used in this module's tests.
163 *
164 */
kernel_init_objects(void)165 static void kernel_init_objects(void)
166 {
167 k_sem_init(&reply_timeout, 0, UINT_MAX);
168 k_timer_init(&timer, NULL, NULL);
169 k_fifo_init(&timeout_order_fifo);
170 }
171
172 /**
173 * @brief A wrapper for irq_lock()
174 *
175 * @return irq_lock() return value
176 */
irq_lock_wrapper(int unused)177 int irq_lock_wrapper(int unused)
178 {
179 ARG_UNUSED(unused);
180
181 return irq_lock();
182 }
183
184 /**
185 * @brief A wrapper for irq_unlock()
186 */
irq_unlock_wrapper(int imask)187 void irq_unlock_wrapper(int imask)
188 {
189 irq_unlock(imask);
190 }
191
192 /**
193 * @brief A wrapper for irq_disable()
194 *
195 * @return @a irq
196 */
irq_disable_wrapper(int irq)197 int irq_disable_wrapper(int irq)
198 {
199 irq_disable(irq);
200 return irq;
201 }
202
203 /**
204 * @brief A wrapper for irq_enable()
205 */
irq_enable_wrapper(int irq)206 void irq_enable_wrapper(int irq)
207 {
208 irq_enable(irq);
209 }
210
211 #if defined(HAS_POWERSAVE_INSTRUCTION)
212 #if defined(CONFIG_TICKLESS_KERNEL)
213 static struct k_timer idle_timer;
214
215 static volatile bool idle_timer_done;
216
idle_timer_expiry_function(struct k_timer * timer_id)217 static void idle_timer_expiry_function(struct k_timer *timer_id)
218 {
219 k_timer_stop(&idle_timer);
220 idle_timer_done = true;
221 }
222
_test_kernel_cpu_idle(int atomic)223 static void _test_kernel_cpu_idle(int atomic)
224 {
225 uint64_t t0, dt;
226 unsigned int i, key;
227 uint32_t dur = k_ms_to_ticks_ceil32(10);
228 uint32_t slop = 1 + k_ms_to_ticks_ceil32(1);
229 int idle_loops;
230
231 /* Set up a time to trigger events to exit idle mode */
232 k_timer_init(&idle_timer, idle_timer_expiry_function, NULL);
233
234 for (i = 0; i < 5; i++) {
235 k_usleep(1);
236 t0 = k_uptime_ticks();
237 idle_loops = 0;
238 idle_timer_done = false;
239 k_timer_start(&idle_timer, K_TICKS(dur), K_NO_WAIT);
240 key = irq_lock();
241 do {
242 if (atomic) {
243 k_cpu_atomic_idle(key);
244 } else {
245 k_cpu_idle();
246 }
247 } while ((idle_loops++ < CONFIG_MAX_IDLE_WAKES) && (idle_timer_done == false));
248 dt = k_uptime_ticks() - t0;
249 zassert_true(abs((int32_t) (dt - dur)) <= slop,
250 "Inaccurate wakeup, idled for %d ticks, expected %d",
251 dt, dur);
252 }
253 }
254
255 #else /* CONFIG_TICKLESS_KERNEL */
_test_kernel_cpu_idle(int atomic)256 static void _test_kernel_cpu_idle(int atomic)
257 {
258 int tms, tms2;
259 int i;
260
261 /* Align to a "ms boundary". */
262 tms = k_uptime_get_32();
263 while (tms == k_uptime_get_32()) {
264 Z_SPIN_DELAY(50);
265 }
266
267 tms = k_uptime_get_32();
268 for (i = 0; i < 5; i++) { /* Repeat the test five times */
269 if (atomic) {
270 unsigned int key = irq_lock();
271
272 k_cpu_atomic_idle(key);
273 } else {
274 k_cpu_idle();
275 }
276 /* calculating milliseconds per tick*/
277 tms += k_ticks_to_ms_floor64(1);
278 tms2 = k_uptime_get_32();
279 zassert_false(tms2 < tms, "Bad ms per tick value computed,"
280 "got %d which is less than %d\n",
281 tms2, tms);
282 }
283 }
284 #endif /* CONFIG_TICKLESS_KERNEL */
285
286 /**
287 * @brief Test cpu idle function
288 *
289 * @details
290 * Test Objective:
291 * - The kernel architecture provide an idle function to be run when the system
292 * has no work for the current CPU
293 * - This routine tests the k_cpu_atomic_idle() routine
294 *
295 * Testing techniques
296 * - Functional and black box testing
297 * - Interface testing
298 *
299 * Prerequisite Condition:
300 * - HAS_POWERSAVE_INSTRUCTION is set
301 *
302 * Input Specifications:
303 * - N/A
304 *
305 * Test Procedure:
306 * -# Record system time before cpu enters idle state
307 * -# Enter cpu idle state by k_cpu_atomic_idle()
308 * -# Record system time after cpu idle state is interrupted
309 * -# Compare the two system time values.
310 *
311 * Expected Test Result:
312 * - cpu enters idle state for a given time
313 *
314 * Pass/Fail criteria:
315 * - Success if the cpu enters idle state, failure otherwise.
316 *
317 * Assumptions and Constraints
318 * - N/A
319 *
320 * @see k_cpu_atomic_idle()
321 * @ingroup kernel_context_tests
322 */
ZTEST(context_cpu_idle,test_cpu_idle_atomic)323 ZTEST(context_cpu_idle, test_cpu_idle_atomic)
324 {
325 #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
326 ztest_test_skip();
327 #else
328 _test_kernel_cpu_idle(1);
329 #endif
330 }
331
332 /**
333 * @brief Test cpu idle function
334 *
335 * @details
336 * Test Objective:
337 * - The kernel architecture provide an idle function to be run when the system
338 * has no work for the current CPU
339 * - This routine tests the k_cpu_idle() routine
340 *
341 * Testing techniques
342 * - Functional and black box testing
343 * - Interface testing
344 *
345 * Prerequisite Condition:
346 * - HAS_POWERSAVE_INSTRUCTION is set
347 *
348 * Input Specifications:
349 * - N/A
350 *
351 * Test Procedure:
352 * -# Record system time before cpu enters idle state
353 * -# Enter cpu idle state by k_cpu_idle()
354 * -# Record system time after cpu idle state is interrupted
355 * -# Compare the two system time values.
356 *
357 * Expected Test Result:
358 * - cpu enters idle state for a given time
359 *
360 * Pass/Fail criteria:
361 * - Success if the cpu enters idle state, failure otherwise.
362 *
363 * Assumptions and Constraints
364 * - N/A
365 *
366 * @see k_cpu_idle()
367 * @ingroup kernel_context_tests
368 */
ZTEST(context_cpu_idle,test_cpu_idle)369 ZTEST(context_cpu_idle, test_cpu_idle)
370 {
371 _test_kernel_cpu_idle(0);
372 }
373
374 #else /* HAS_POWERSAVE_INSTRUCTION */
ZTEST(context_cpu_idle,test_cpu_idle)375 ZTEST(context_cpu_idle, test_cpu_idle)
376 {
377 ztest_test_skip();
378 }
ZTEST(context_cpu_idle,test_cpu_idle_atomic)379 ZTEST(context_cpu_idle, test_cpu_idle_atomic)
380 {
381 ztest_test_skip();
382 }
383 #endif
384
_test_kernel_interrupts(disable_int_func disable_int,enable_int_func enable_int,int irq)385 static void _test_kernel_interrupts(disable_int_func disable_int,
386 enable_int_func enable_int, int irq)
387 {
388 unsigned long long count = 1ull;
389 unsigned long long i = 0;
390 int tick;
391 int tick2;
392 int imask;
393
394 /* Align to a "tick boundary" */
395 tick = sys_clock_tick_get_32();
396 while (sys_clock_tick_get_32() == tick) {
397 Z_SPIN_DELAY(1000);
398 }
399
400 tick++;
401 while (sys_clock_tick_get_32() == tick) {
402 Z_SPIN_DELAY(1000);
403 count++;
404 }
405
406 /*
407 * Inflate <count> so that when we loop later, many ticks should have
408 * elapsed during the loop. This later loop will not exactly match the
409 * previous loop, but it should be close enough in structure that when
410 * combined with the inflated count, many ticks will have passed.
411 */
412
413 count <<= 4;
414
415 imask = disable_int(irq);
416 tick = sys_clock_tick_get_32();
417 for (i = 0; i < count; i++) {
418 sys_clock_tick_get_32();
419 Z_SPIN_DELAY(1000);
420 }
421
422 tick2 = sys_clock_tick_get_32();
423
424 /*
425 * Re-enable interrupts before returning (for both success and failure
426 * cases).
427 */
428 enable_int(imask);
429
430 /* In TICKLESS, current time is retrieved from a hardware
431 * counter and ticks DO advance with interrupts locked!
432 */
433 if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
434 zassert_equal(tick2, tick,
435 "tick advanced with interrupts locked");
436 }
437
438 /* Now repeat with interrupts unlocked. */
439 for (i = 0; i < count; i++) {
440 sys_clock_tick_get_32();
441 Z_SPIN_DELAY(1000);
442 }
443
444 tick2 = sys_clock_tick_get_32();
445 zassert_not_equal(tick, tick2,
446 "tick didn't advance as expected");
447 }
448
449 /**
450 * @brief Test routines for disabling and enabling interrupts
451 *
452 * @ingroup kernel_context_tests
453 *
454 * @details
455 * Test Objective:
456 * - To verify kernel architecture layer shall provide a mechanism to
457 * selectively disable and enable specific numeric interrupts.
458 * - This routine tests the routines for disabling and enabling interrupts.
459 * These include irq_lock() and irq_unlock().
460 *
461 * Testing techniques:
462 * - Interface testing, function and black box testing,
463 * dynamic analysis and testing
464 *
465 * Prerequisite Conditions:
466 * - CONFIG_TICKLESS_KERNEL is not set.
467 *
468 * Input Specifications:
469 * - N/A
470 *
471 * Test Procedure:
472 * -# Do action to align to a tick boundary.
473 * -# Left shift 4 bits for the value of counts.
474 * -# Call irq_lock() and restore its return value to imask.
475 * -# Call sys_clock_tick_get_32() and store its return value to tick.
476 * -# Repeat counts of calling sys_clock_tick_get_32().
477 * -# Call sys_clock_tick_get_32() and store its return value to tick2.
478 * -# Call irq_unlock() with parameter imask.
479 * -# Check if tick is equal to tick2.
480 * -# Repeat counts of calling sys_clock_tick_get_32().
481 * -# Call sys_clock_tick_get_32() and store its return value to tick2.
482 * -# Check if tick is NOT equal to tick2.
483 *
484 * Expected Test Result:
485 * - The ticks shall not increase while interrupt locked.
486 *
487 * Pass/Fail Criteria:
488 * - Successful if check points in test procedure are all passed, otherwise
489 * failure.
490 *
491 * Assumptions and Constraints:
492 * - N/A
493 *
494 * @see irq_lock(), irq_unlock()
495 */
ZTEST(context,test_interrupts)496 ZTEST(context, test_interrupts)
497 {
498 /* IRQ locks don't prevent ticks from advancing in tickless mode */
499 if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
500 ztest_test_skip();
501 }
502
503 _test_kernel_interrupts(irq_lock_wrapper, irq_unlock_wrapper, -1);
504 }
505
506 /**
507 * @brief Test routines for disabling and enabling interrupts (disable timer)
508 *
509 * @ingroup kernel_context_tests
510 *
511 * @details
512 * Test Objective:
513 * - To verify the kernel architecture layer shall provide a mechanism to
514 * simultaneously mask all local CPU interrupts and return the previous mask
515 * state for restoration.
516 * - This routine tests the routines for disabling and enabling interrupts.
517 * These include irq_disable() and irq_enable().
518 *
519 * Testing techniques:
520 * - Interface testing, function and black box testing,
521 * dynamic analysis and testing
522 *
523 * Prerequisite Conditions:
524 * - TICK_IRQ is defined.
525 *
526 * Input Specifications:
527 * - N/A
528 *
529 * Test Procedure:
530 * -# Do action to align to a tick boundary.
531 * -# Left shift 4 bit for the value of counts.
532 * -# Call irq_disable() and restore its return value to imask.
533 * -# Call sys_clock_tick_get_32() and store its return value to tick.
534 * -# Repeat counts of calling sys_clock_tick_get_32().
535 * -# Call sys_clock_tick_get_32() and store its return value to tick2.
536 * -# Call irq_enable() with parameter imask.
537 * -# Check if tick is equal to tick2.
538 * -# Repeat counts of calling sys_clock_tick_get_32().
539 * -# Call sys_clock_tick_get_32() and store its return value to tick2.
540 * -# Check if tick is NOT equal to tick2.
541 *
542 * Expected Test Result:
543 * - The ticks shall not increase while interrupt locked.
544 *
545 * Pass/Fail Criteria:
546 * - Successful if check points in test procedure are all passed, otherwise
547 * failure.
548 *
549 * Assumptions and Constraints:
550 * - Note that this test works by disabling the timer interrupt
551 * directly, without any interaction with the timer driver or
552 * timeout subsystem. NOT ALL ARCHITECTURES will latch and deliver
553 * a timer interrupt that arrives while the interrupt is disabled,
554 * which means that the timeout list will become corrupted (because
555 * it contains items that should have expired in the past). Any use
556 * of kernel timeouts after completion of this test is disallowed.
557 * RUN THIS TEST LAST IN THE SUITE.
558 *
559 * @see irq_disable(), irq_enable()
560 */
ZTEST(context_one_cpu,test_timer_interrupts)561 ZTEST(context_one_cpu, test_timer_interrupts)
562 {
563 #if (defined(TICK_IRQ) && defined(CONFIG_TICKLESS_KERNEL))
564 /* Disable interrupts coming from the timer. */
565 _test_kernel_interrupts(irq_disable_wrapper, irq_enable_wrapper, TICK_IRQ);
566 #else
567 ztest_test_skip();
568 #endif
569 }
570
571 /**
572 * @brief Test some context routines
573 *
574 * @details
575 * Test Objective:
576 * - Thread context handles derived from context switches must be able to be
577 * restored upon interrupt exit
578 *
579 * Testing techniques
580 * - Functional and black box testing
581 * - Interface testing
582 *
583 * Prerequisite Condition:
584 * - N/A
585 *
586 * Input Specifications:
587 * - N/A
588 *
589 * Test Procedure:
590 * -# Set priority of current thread to 0 as a preemptible thread
591 * -# Trap to interrupt context, get thread id of the interrupted thread and
592 * pass back to that thread.
593 * -# Return to thread context and make sure this context is interrupted by
594 * comparing its thread ID and the thread ID passed by isr.
595 * -# Pass command to isr to check whether the isr is executed in interrupt
596 * context
597 * -# When return to thread context, check the return value of command.
598 *
599 * Expected Test Result:
600 * - Thread context restored upon interrupt exit
601 *
602 * Pass/Fail criteria:
603 * - Success if context of thread restored correctly, failure otherwise.
604 *
605 * Assumptions and Constraints
606 * - N/A
607 *
608 * @ingroup kernel_context_tests
609 * @see k_current_get(), k_is_in_isr()
610 */
ZTEST(context,test_ctx_thread)611 ZTEST(context, test_ctx_thread)
612 {
613 k_tid_t self_thread_id;
614
615 k_thread_priority_set(k_current_get(), 0);
616
617 TC_PRINT("Testing k_current_get() from an ISR and thread\n");
618
619 self_thread_id = k_current_get();
620 isr_info.command = THREAD_SELF_CMD;
621 isr_info.error = 0;
622 /* isr_info is modified by the isr_handler routine */
623 isr_handler_trigger();
624
625 zassert_false(isr_info.error, "ISR detected an error");
626
627 zassert_equal(isr_info.data, (void *)self_thread_id,
628 "ISR context ID mismatch");
629
630 TC_PRINT("Testing k_is_in_isr() from an ISR\n");
631 isr_info.command = EXEC_CTX_TYPE_CMD;
632 isr_info.error = 0;
633 isr_handler_trigger();
634
635 zassert_false(isr_info.error, "ISR detected an error");
636
637 zassert_equal(isr_info.value, K_ISR,
638 "isr_info.value was not K_ISR");
639
640 TC_PRINT("Testing k_is_in_isr() from a preemptible thread\n");
641 zassert_false(k_is_in_isr(), "Should not be in ISR context");
642
643 zassert_false(_current->base.prio < 0,
644 "Current thread should have preemptible priority: %d",
645 _current->base.prio);
646
647 }
648
649 /**
650 * @brief Test the various context/thread routines from a cooperative thread
651 *
652 * This routines tests the k_current_get() and k_is_in_isr() routines from both
653 * a thread and an ISR (that interrupted a cooperative thread). Checking those
654 * routines with preemptible threads are done elsewhere.
655 *
656 * @see k_current_get(), k_is_in_isr()
657 */
_test_kernel_thread(k_tid_t _thread_id)658 static void _test_kernel_thread(k_tid_t _thread_id)
659 {
660 k_tid_t self_thread_id;
661
662 self_thread_id = k_current_get();
663 zassert_true((self_thread_id != _thread_id), "thread id matches parent thread");
664
665 isr_info.command = THREAD_SELF_CMD;
666 isr_info.error = 0;
667 isr_handler_trigger();
668 /*
669 * Either the ISR detected an error, or the ISR context ID
670 * does not match the interrupted thread's ID.
671 */
672 zassert_false((isr_info.error || (isr_info.data != (void *)self_thread_id)),
673 "Thread ID taken during ISR != calling thread");
674
675 isr_info.command = EXEC_CTX_TYPE_CMD;
676 isr_info.error = 0;
677 isr_handler_trigger();
678 zassert_false((isr_info.error || (isr_info.value != K_ISR)),
679 "k_is_in_isr() when called from an ISR is false");
680
681 zassert_false(k_is_in_isr(), "k_is_in_isr() when called from a thread is true");
682
683 zassert_false((_current->base.prio >= 0),
684 "thread is not a cooperative thread");
685 }
686
687 /**
688 *
689 * @brief Entry point to the thread's helper
690 *
691 * This routine is the entry point to the thread's helper thread. It is used to
692 * help test the behavior of the k_yield() routine.
693 *
694 * @param arg1 unused
695 * @param arg2 unused
696 * @param arg3 unused
697 *
698 */
699
thread_helper(void * arg1,void * arg2,void * arg3)700 static void thread_helper(void *arg1, void *arg2, void *arg3)
701 {
702 k_tid_t self_thread_id;
703
704 ARG_UNUSED(arg1);
705 ARG_UNUSED(arg2);
706 ARG_UNUSED(arg3);
707
708 /*
709 * This thread starts off at a higher priority than thread_entry().
710 * Thus, it should execute immediately.
711 */
712 thread_evidence++;
713
714 /* Test that helper will yield to a thread of equal priority */
715 self_thread_id = k_current_get();
716
717 /* Lower priority to that of thread_entry() */
718 k_thread_priority_set(self_thread_id, self_thread_id->base.prio + 1);
719
720 k_yield(); /* Yield to thread of equal priority */
721
722 thread_evidence++;
723 /* thread_evidence should now be 2 */
724
725 }
726
727 /**
728 * @brief Entry point to thread started by another thread
729 *
730 * This routine is the entry point to the thread started by the thread.
731 */
k_yield_entry(void * arg0,void * arg1,void * arg2)732 static void k_yield_entry(void *arg0, void *arg1, void *arg2)
733 {
734 k_tid_t self_thread_id;
735
736 ARG_UNUSED(arg0);
737 ARG_UNUSED(arg1);
738 ARG_UNUSED(arg2);
739
740 thread_evidence++; /* Prove that the thread has run */
741 k_sem_take(&sem_thread, K_FOREVER);
742
743 /*
744 * Start a thread of higher priority. Note that since the new thread is
745 * being started from a thread, it will not automatically switch to the
746 * thread as it would if done from another thread.
747 */
748 self_thread_id = k_current_get();
749 thread_evidence = 0;
750
751 k_thread_create(&thread_data2, thread_stack2, THREAD_STACKSIZE,
752 thread_helper, NULL, NULL, NULL,
753 K_PRIO_COOP(THREAD_PRIORITY - 1), 0, K_NO_WAIT);
754
755 zassert_equal(thread_evidence, 0,
756 "Helper created at higher priority ran prematurely.");
757
758 /*
759 * Validate the thread is allowed to yield
760 */
761 zassert_true(k_can_yield(), "Thread incorrectly detected it could not yield");
762
763 /*
764 * Test that the thread will yield to the higher priority helper.
765 * thread_evidence is still 0.
766 */
767 k_yield();
768
769 zassert_not_equal(thread_evidence, 0,
770 "k_yield() did not yield to a higher priority thread: %d",
771 thread_evidence);
772
773 zassert_false((thread_evidence > 1),
774 "k_yield() did not yield to an equal priority thread: %d",
775 thread_evidence);
776
777 /*
778 * Raise the priority of thread_entry(). Calling k_yield() should
779 * not result in switching to the helper.
780 */
781 k_thread_priority_set(self_thread_id, self_thread_id->base.prio - 1);
782 k_yield();
783
784 zassert_equal(thread_evidence, 1,
785 "k_yield() yielded to a lower priority thread");
786
787 /*
788 * Block on sem_thread. This will allow the helper thread to
789 * complete. The main thread will wake this thread.
790 */
791 k_sem_take(&sem_thread, K_FOREVER);
792 }
793
kernel_thread_entry(void * _thread_id,void * arg1,void * arg2)794 static void kernel_thread_entry(void *_thread_id, void *arg1, void *arg2)
795 {
796 ARG_UNUSED(arg1);
797 ARG_UNUSED(arg2);
798
799 thread_evidence++; /* Prove that the thread has run */
800 k_sem_take(&sem_thread, K_FOREVER);
801
802 _test_kernel_thread((k_tid_t) _thread_id);
803
804 }
805
806 /*
807 * @brief Timeout tests
808 *
809 * Test the k_sleep() API, as well as the k_thread_create() ones.
810 */
811 struct timeout_order {
812 void *link_in_fifo;
813 int32_t timeout;
814 int timeout_order;
815 int q_order;
816 };
817
818 struct timeout_order timeouts[] = {
819 { 0, 1000, 2, 0 },
820 { 0, 1500, 4, 1 },
821 { 0, 500, 0, 2 },
822 { 0, 750, 1, 3 },
823 { 0, 1750, 5, 4 },
824 { 0, 2000, 6, 5 },
825 { 0, 1250, 3, 6 },
826 };
827
828 #define NUM_TIMEOUT_THREADS ARRAY_SIZE(timeouts)
829 static K_THREAD_STACK_ARRAY_DEFINE(timeout_stacks, NUM_TIMEOUT_THREADS,
830 THREAD_STACKSIZE2);
831 static struct k_thread timeout_threads[NUM_TIMEOUT_THREADS];
832
833 /* a thread busy waits */
busy_wait_thread(void * mseconds,void * arg2,void * arg3)834 static void busy_wait_thread(void *mseconds, void *arg2, void *arg3)
835 {
836 uint32_t usecs;
837
838 ARG_UNUSED(arg2);
839 ARG_UNUSED(arg3);
840
841 usecs = POINTER_TO_INT(mseconds) * 1000;
842
843 k_busy_wait(usecs);
844
845 /* FIXME: Broken on Nios II, see #22956 */
846 #ifndef CONFIG_NIOS2
847 int key = arch_irq_lock();
848
849 k_busy_wait(usecs);
850 arch_irq_unlock(key);
851 #endif
852
853 /*
854 * Ideally the test should verify that the correct number of ticks
855 * have elapsed. However, when running under QEMU, the tick interrupt
856 * may be processed on a very irregular basis, meaning that far
857 * fewer than the expected number of ticks may occur for a given
858 * number of clock cycles vs. what would ordinarily be expected.
859 *
860 * Consequently, the best we can do for now to test busy waiting is
861 * to invoke the API and verify that it returns. (If it takes way
862 * too long, or never returns, the main test thread may be able to
863 * time out and report an error.)
864 */
865
866 k_sem_give(&reply_timeout);
867 }
868
869 /* a thread sleeps and times out, then reports through a fifo */
thread_sleep(void * delta,void * arg2,void * arg3)870 static void thread_sleep(void *delta, void *arg2, void *arg3)
871 {
872 int64_t timestamp;
873 int timeout = POINTER_TO_INT(delta);
874
875 ARG_UNUSED(arg2);
876 ARG_UNUSED(arg3);
877
878 timestamp = k_uptime_get();
879 k_msleep(timeout);
880 timestamp = k_uptime_get() - timestamp;
881
882 int slop = MAX(k_ticks_to_ms_floor64(2), 1);
883
884 if (timestamp < timeout || timestamp > timeout + slop) {
885 TC_ERROR("timestamp out of range, got %d\n", (int)timestamp);
886 return;
887 }
888
889 k_sem_give(&reply_timeout);
890 }
891
892 /* a thread is started with a delay, then it reports that it ran via a fifo */
delayed_thread(void * num,void * arg2,void * arg3)893 static void delayed_thread(void *num, void *arg2, void *arg3)
894 {
895 struct timeout_order *timeout = &timeouts[POINTER_TO_INT(num)];
896
897 ARG_UNUSED(arg2);
898 ARG_UNUSED(arg3);
899
900 TC_PRINT(" thread (q order: %d, t/o: %d) is running\n",
901 timeout->q_order, timeout->timeout);
902
903 k_fifo_put(&timeout_order_fifo, timeout);
904 }
905
906 /**
907 * @brief Test timeouts
908 *
909 * @ingroup kernel_context_tests
910 *
911 * @see k_busy_wait(), k_sleep()
912 */
ZTEST(context_one_cpu,test_busy_wait)913 ZTEST(context_one_cpu, test_busy_wait)
914 {
915 int32_t timeout;
916 int rv;
917
918 timeout = 20; /* in ms */
919
920 k_thread_create(&timeout_threads[0], timeout_stacks[0],
921 THREAD_STACKSIZE2, busy_wait_thread,
922 INT_TO_POINTER(timeout), NULL,
923 NULL, K_PRIO_COOP(THREAD_PRIORITY), 0, K_NO_WAIT);
924
925 rv = k_sem_take(&reply_timeout, K_MSEC(timeout * 2 * 2));
926
927 zassert_false(rv, " *** thread timed out waiting for " "k_busy_wait()");
928 }
929
930 /**
931 * @brief Test timeouts
932 *
933 * @ingroup kernel_context_tests
934 *
935 * @see k_sleep()
936 */
ZTEST(context_one_cpu,test_k_sleep)937 ZTEST(context_one_cpu, test_k_sleep)
938 {
939 struct timeout_order *data;
940 int32_t timeout;
941 int rv;
942 int i;
943
944
945 timeout = 50;
946
947 k_thread_create(&timeout_threads[0], timeout_stacks[0],
948 THREAD_STACKSIZE2, thread_sleep,
949 INT_TO_POINTER(timeout), NULL,
950 NULL, K_PRIO_COOP(THREAD_PRIORITY), 0, K_NO_WAIT);
951
952 rv = k_sem_take(&reply_timeout, K_MSEC(timeout * 2));
953 zassert_equal(rv, 0, " *** thread timed out waiting for thread on "
954 "k_sleep().");
955
956 /* test k_thread_create() without cancellation */
957 TC_PRINT("Testing k_thread_create() without cancellation\n");
958
959 for (i = 0; i < NUM_TIMEOUT_THREADS; i++) {
960 k_thread_create(&timeout_threads[i], timeout_stacks[i],
961 THREAD_STACKSIZE2,
962 delayed_thread,
963 INT_TO_POINTER(i), NULL, NULL,
964 K_PRIO_COOP(5), 0,
965 K_MSEC(timeouts[i].timeout));
966 }
967 for (i = 0; i < NUM_TIMEOUT_THREADS; i++) {
968 data = k_fifo_get(&timeout_order_fifo, K_MSEC(750));
969 zassert_not_null(data, " *** timeout while waiting for"
970 " delayed thread");
971
972 zassert_equal(data->timeout_order, i,
973 " *** wrong delayed thread ran (got %d, "
974 "expected %d)\n", data->timeout_order, i);
975
976 TC_PRINT(" got thread (q order: %d, t/o: %d) as expected\n",
977 data->q_order, data->timeout);
978 }
979
980 /* ensure no more thread fire */
981 data = k_fifo_get(&timeout_order_fifo, K_MSEC(750));
982
983 zassert_false(data, " *** got something unexpected in the fifo");
984
985 /* test k_thread_create() with cancellation */
986 TC_PRINT("Testing k_thread_create() with cancellations\n");
987
988 int cancellations[] = { 0, 3, 4, 6 };
989 int num_cancellations = ARRAY_SIZE(cancellations);
990 int next_cancellation = 0;
991
992 k_tid_t delayed_threads[NUM_TIMEOUT_THREADS];
993
994 for (i = 0; i < NUM_TIMEOUT_THREADS; i++) {
995 k_tid_t id;
996
997 id = k_thread_create(&timeout_threads[i], timeout_stacks[i],
998 THREAD_STACKSIZE2, delayed_thread,
999 INT_TO_POINTER(i), NULL, NULL,
1000 K_PRIO_COOP(5), 0,
1001 K_MSEC(timeouts[i].timeout));
1002
1003 delayed_threads[i] = id;
1004 }
1005
1006 for (i = 0; i < NUM_TIMEOUT_THREADS; i++) {
1007 int j;
1008
1009 if (i == cancellations[next_cancellation]) {
1010 TC_PRINT(" cancelling "
1011 "[q order: %d, t/o: %d, t/o order: %d]\n",
1012 timeouts[i].q_order, timeouts[i].timeout, i);
1013
1014 for (j = 0; j < NUM_TIMEOUT_THREADS; j++) {
1015 if (timeouts[j].timeout_order == i) {
1016 break;
1017 }
1018 }
1019
1020 if (j < NUM_TIMEOUT_THREADS) {
1021 k_thread_abort(delayed_threads[j]);
1022 ++next_cancellation;
1023 continue;
1024 }
1025 }
1026
1027 data = k_fifo_get(&timeout_order_fifo, K_MSEC(2750));
1028
1029 zassert_not_null(data, " *** timeout while waiting for"
1030 " delayed thread");
1031
1032 zassert_equal(data->timeout_order, i,
1033 " *** wrong delayed thread ran (got %d, "
1034 "expected %d)\n", data->timeout_order, i);
1035
1036 TC_PRINT(" got (q order: %d, t/o: %d, t/o order %d) "
1037 "as expected\n", data->q_order, data->timeout,
1038 data->timeout_order);
1039 }
1040
1041 zassert_equal(num_cancellations, next_cancellation,
1042 " *** wrong number of cancellations (expected %d, "
1043 "got %d\n", num_cancellations, next_cancellation);
1044
1045 /* ensure no more thread fire */
1046 data = k_fifo_get(&timeout_order_fifo, K_MSEC(750));
1047 zassert_false(data, " *** got something unexpected in the fifo");
1048
1049 }
1050
1051 /**
1052 *
1053 * @brief Test the k_yield() routine
1054 *
1055 * @ingroup kernel_context_tests
1056 *
1057 * Tests the k_yield() routine. It starts another thread
1058 * (thus also testing k_thread_create()) and checks that behavior of
1059 * k_yield() against the a higher priority thread,
1060 * a lower priority thread, and another thread of equal priority.
1061 *
1062 * @see k_yield()
1063 */
ZTEST(context_one_cpu,test_k_yield)1064 ZTEST(context_one_cpu, test_k_yield)
1065 {
1066 thread_evidence = 0;
1067 k_thread_priority_set(k_current_get(), 0);
1068
1069 k_sem_init(&sem_thread, 0, UINT_MAX);
1070
1071 k_thread_create(&thread_data1, thread_stack1, THREAD_STACKSIZE,
1072 k_yield_entry, NULL, NULL,
1073 NULL, K_PRIO_COOP(THREAD_PRIORITY), 0, K_NO_WAIT);
1074
1075 zassert_equal(thread_evidence, 1,
1076 "Thread did not execute as expected!: %d", thread_evidence);
1077
1078 k_sem_give(&sem_thread);
1079 k_sem_give(&sem_thread);
1080 k_sem_give(&sem_thread);
1081 }
1082
1083 /**
1084 * @brief Test kernel thread creation
1085 *
1086 * @ingroup kernel_context_tests
1087 *
1088 * @see k_thread_create
1089 */
1090
ZTEST(context_one_cpu,test_thread)1091 ZTEST(context_one_cpu, test_thread)
1092 {
1093
1094 k_thread_create(&thread_data3, thread_stack3, THREAD_STACKSIZE,
1095 kernel_thread_entry, NULL, NULL,
1096 NULL, K_PRIO_COOP(THREAD_PRIORITY), 0, K_NO_WAIT);
1097
1098 }
1099
context_setup(void)1100 static void *context_setup(void)
1101 {
1102 kernel_init_objects();
1103
1104 return NULL;
1105 }
1106
1107 ZTEST_SUITE(context_cpu_idle, NULL, context_setup, NULL, NULL, NULL);
1108
1109 ZTEST_SUITE(context, NULL, context_setup, NULL, NULL, NULL);
1110
1111 ZTEST_SUITE(context_one_cpu, NULL, context_setup,
1112 ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
1113