Skip to content

Commit 138be8e

Browse files
wopu-otnashif
authored andcommitted
tests: Add test for MetaIRQ preemption of cooperative thread
Test that meta-IRQ returns to the cooperative thread it interrupted, and not to whichever thread is highest priority at that point. Signed-off-by: Wolfgang Puffitsch <[email protected]>
1 parent 28af508 commit 138be8e

File tree

4 files changed

+160
-0
lines changed

4 files changed

+160
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.13.1)
4+
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
5+
project(preempt)
6+
7+
FILE(GLOB app_sources src/*.c)
8+
target_sources(app PRIVATE ${app_sources})

tests/kernel/sched/metairq/prj.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CONFIG_ZTEST=y
2+
CONFIG_MP_NUM_CPUS=1
3+
CONFIG_NUM_METAIRQ_PRIORITIES=1

tests/kernel/sched/metairq/src/main.c

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

0 commit comments

Comments
 (0)