1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** Thread-Metric Component */
15 /** */
16 /** Interrupt Preemption Processing Test */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21
22 /**************************************************************************/
23 /* */
24 /* FUNCTION RELEASE */
25 /* */
26 /* tm_interrupt_preemption_processing_test PORTABLE C */
27 /* 6.1.7 */
28 /* AUTHOR */
29 /* */
30 /* William E. Lamie, Microsoft Corporation */
31 /* */
32 /* DESCRIPTION */
33 /* */
34 /* This file defines the preemptive scheduling test. */
35 /* */
36 /* RELEASE HISTORY */
37 /* */
38 /* DATE NAME DESCRIPTION */
39 /* */
40 /* 10-15-2021 William E. Lamie Initial Version 6.1.7 */
41 /* */
42 /**************************************************************************/
43
44 #include "tm_api.h"
45
46
47 /* Define the counters used in the demo application... */
48
49 unsigned long tm_interrupt_preemption_thread_0_counter;
50 unsigned long tm_interrupt_preemption_thread_1_counter;
51 unsigned long tm_interrupt_preemption_handler_counter;
52
53
54 /* Define the test thread prototypes. */
55
56 void tm_interrupt_preemption_thread_0_entry(void);
57 void tm_interrupt_preemption_thread_1_entry(void);
58 void tm_interrupt_preemption_handler_entry(void);
59
60
61 /* Define the reporting thread prototype. */
62
63 void tm_interrupt_preemption_thread_report(void);
64
65
66 /* Define the interrupt handler. This must be called from the RTOS. */
67
68 void tm_interrupt_preemption_handler(void);
69
70
71 /* Define the initialization prototype. */
72
73 void tm_interrupt_preemption_processing_initialize(void);
74
75
76 /* Define main entry point. */
77
tm_main()78 void tm_main()
79 {
80
81 /* Initialize the test. */
82 tm_initialize(tm_interrupt_preemption_processing_initialize);
83 }
84
85
86 /* Define the interrupt processing test initialization. */
87
tm_interrupt_preemption_processing_initialize(void)88 void tm_interrupt_preemption_processing_initialize(void)
89 {
90
91 /* Create interrupt thread at priority 3. */
92 tm_thread_create(0, 3, tm_interrupt_preemption_thread_0_entry);
93
94 /* Create thread that generates the interrupt at priority 10. */
95 tm_thread_create(1, 10, tm_interrupt_preemption_thread_1_entry);
96
97 /* Resume just thread 1. */
98 tm_thread_resume(1);
99
100 /* Create the reporting thread. It will preempt the other
101 threads and print out the test results. */
102 tm_thread_create(5, 2, tm_interrupt_preemption_thread_report);
103 tm_thread_resume(5);
104 }
105
106
107 /* Define the interrupt thread. This thread is resumed from the
108 interrupt handler. It runs and suspends. */
tm_interrupt_preemption_thread_0_entry(void)109 void tm_interrupt_preemption_thread_0_entry(void)
110 {
111
112 while(1)
113 {
114
115 /* Increment this thread's counter. */
116 tm_interrupt_preemption_thread_0_counter++;
117
118 /* Suspend. This will allow the thread generating the
119 interrupt to run again. */
120 tm_thread_suspend(0);
121 }
122 }
123
124 /* Define the thread that generates the interrupt. */
tm_interrupt_preemption_thread_1_entry(void)125 void tm_interrupt_preemption_thread_1_entry(void)
126 {
127
128 while(1)
129 {
130
131 /* Force an interrupt. The underlying RTOS must see that the
132 the interrupt handler is called from the appropriate software
133 interrupt or trap. */
134 TM_CAUSE_INTERRUPT
135
136 /* We won't get back here until the interrupt processing is complete,
137 including the execution of the higher priority thread made ready
138 by the interrupt. */
139
140 /* Increment this thread's counter. */
141 tm_interrupt_preemption_thread_1_counter++;
142 }
143 }
144
145
146 /* Define the interrupt handler. This must be called from the RTOS trap handler.
147 To be fair, it must behave just like a processor interrupt, i.e. it must save
148 the full context of the interrupted thread during the preemption processing. */
tm_interrupt_preemption_handler(void)149 void tm_interrupt_preemption_handler(void)
150 {
151
152 /* Increment the interrupt count. */
153 tm_interrupt_preemption_handler_counter++;
154
155 /* Resume the higher priority thread from the ISR. */
156 tm_thread_resume(0);
157 }
158
159
160 /* Define the interrupt test reporting thread. */
tm_interrupt_preemption_thread_report(void)161 void tm_interrupt_preemption_thread_report(void)
162 {
163
164 unsigned long total;
165 unsigned long relative_time;
166 unsigned long last_total;
167 unsigned long average;
168
169
170 /* Initialize the last total. */
171 last_total = 0;
172
173 /* Initialize the relative time. */
174 relative_time = 0;
175
176 while(1)
177 {
178
179 /* Sleep to allow the test to run. */
180 tm_thread_sleep(TM_TEST_DURATION);
181
182 /* Increment the relative time. */
183 relative_time = relative_time + TM_TEST_DURATION;
184
185 /* Print results to the stdio window. */
186 printf("**** Thread-Metric Interrupt Preemption Processing Test **** Relative Time: %lu\n", relative_time);
187
188 /* Calculate the total of all the counters. */
189 total = tm_interrupt_preemption_thread_0_counter + tm_interrupt_preemption_thread_1_counter + tm_interrupt_preemption_handler_counter;
190
191 /* Calculate the average of all the counters. */
192 average = total/3;
193
194 /* See if there are any errors. */
195 if ((tm_interrupt_preemption_thread_0_counter < (average - 1)) ||
196 (tm_interrupt_preemption_thread_0_counter > (average + 1)) ||
197 (tm_interrupt_preemption_thread_1_counter < (average - 1)) ||
198 (tm_interrupt_preemption_thread_1_counter > (average + 1)) ||
199 (tm_interrupt_preemption_handler_counter < (average - 1)) ||
200 (tm_interrupt_preemption_handler_counter > (average + 1)))
201 {
202
203 printf("ERROR: Invalid counter value(s). Interrupt processing test has failed!\n");
204 }
205
206 /* Show the total interrupts for the time period. */
207 printf("Time Period Total: %lu\n\n", tm_interrupt_preemption_handler_counter - last_total);
208
209 /* Save the last total number of interrupts. */
210 last_total = tm_interrupt_preemption_handler_counter;
211 }
212 }
213