Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /* * Copyright (c) 2019 Demant * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr.h> #include <ztest.h> #include <kernel.h> /* * Test that meta-IRQs return to the cooperative thread they preempted. * * A meta-IRQ thread unblocks first a long-running low-priority * cooperative thread, sleeps a little, and then unblocks a * high-priority cooperative thread before the low-priority thread has * finished. The correct behavior is to continue execution of the * low-priority thread and schedule the high-priority thread * afterwards. */ #if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 1 #error Meta-IRQ test requires single-CPU operation #endif #if CONFIG_NUM_METAIRQ_PRIORITIES < 1 #error Need one metairq priority #endif #if CONFIG_NUM_COOP_PRIORITIES < 2 #error Need two cooperative priorities #endif K_SEM_DEFINE(metairq_sem, 0, 1); K_SEM_DEFINE(coop_sem1, 0, 1); K_SEM_DEFINE(coop_sem2, 0, 1); /* Variables to track progress of cooperative threads */ volatile int coop_cnt1; volatile int coop_cnt2; #define WAIT_MS 10 /* Time to wait/sleep between actions */ #define LOOP_CNT 4 /* Number of times low priority thread waits */ /* Meta-IRQ thread */ void metairq_thread(void) { k_sem_take(&metairq_sem, K_FOREVER); printk("metairq start\n"); coop_cnt1 = 0; coop_cnt2 = 0; printk("give sem2\n"); k_sem_give(&coop_sem2); k_sleep(WAIT_MS); printk("give sem1\n"); k_sem_give(&coop_sem1); printk("metairq end\n"); k_sem_give(&metairq_sem); } /* High-priority cooperative thread */ void coop_thread1(void) { int cnt1, cnt2; k_sem_take(&coop_sem1, K_FOREVER); /* Expect that low-priority thread has run to completion */ cnt1 = coop_cnt1; zassert_equal(cnt1, 0, "Unexpected cnt1 at start: %d", cnt1); cnt2 = coop_cnt2; zassert_equal(cnt2, LOOP_CNT, "Unexpected cnt2 at start: %d", cnt2); printk("thread1\n"); coop_cnt1++; /* Expect that both threads have run to completion */ cnt1 = coop_cnt1; zassert_equal(cnt1, 1, "Unexpected cnt1 at end: %d", cnt1); cnt2 = coop_cnt2; zassert_equal(cnt2, LOOP_CNT, "Unexpected cnt2 at end: %d", cnt2); k_sem_give(&coop_sem1); } /* Low-priority cooperative thread */ void coop_thread2(void) { int cnt1, cnt2; k_sem_take(&coop_sem2, K_FOREVER); /* Expect that this is run first */ cnt1 = coop_cnt1; zassert_equal(cnt1, 0, "Unexpected cnt1 at start: %d", cnt1); cnt2 = coop_cnt2; zassert_equal(cnt2, 0, "Unexpected cnt2 at start: %d", cnt2); for (int i = 0; i < LOOP_CNT; i++) { printk("thread2\n"); coop_cnt2++; k_busy_wait(WAIT_MS * 1000); } /* Expect that this runs to completion before high-priority * thread is started */ cnt1 = coop_cnt1; zassert_equal(cnt1, 0, "Unexpected cnt1 at end: %d", cnt1); cnt2 = coop_cnt2; zassert_equal(cnt2, LOOP_CNT, "Unexpected cnt2 at end: %d", cnt2); k_sem_give(&coop_sem2); } K_THREAD_DEFINE(metairq_thread_id, 1024, metairq_thread, 0, 0, 0, K_PRIO_COOP(0), 0, K_NO_WAIT); K_THREAD_DEFINE(coop_thread1_id, 1024, coop_thread1, 0, 0, 0, K_PRIO_COOP(1), 0, K_NO_WAIT); K_THREAD_DEFINE(coop_thread2_id, 1024, coop_thread2, 0, 0, 0, K_PRIO_COOP(2), 0, K_NO_WAIT); void test_preempt(void) { /* Kick off meta-IRQ */ k_sem_give(&metairq_sem); /* Wait for all threads to finish */ k_sem_take(&coop_sem2, K_FOREVER); k_sem_take(&coop_sem1, K_FOREVER); k_sem_take(&metairq_sem, K_FOREVER); } void test_main(void) { ztest_test_suite(suite_preempt, ztest_unit_test(test_preempt)); ztest_run_test_suite(suite_preempt); } |