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 Processing Test */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 /**************************************************************************/
22 /* */
23 /* FUNCTION RELEASE */
24 /* */
25 /* tm_interrupt_processing_test PORTABLE C */
26 /* 6.1.7 */
27 /* AUTHOR */
28 /* */
29 /* William E. Lamie, Microsoft Corporation */
30 /* */
31 /* DESCRIPTION */
32 /* */
33 /* This file defines the No-preemption interrupt processing test. */
34 /* */
35 /* RELEASE HISTORY */
36 /* */
37 /* DATE NAME DESCRIPTION */
38 /* */
39 /* 10-15-2021 William E. Lamie Initial Version 6.1.7 */
40 /* */
41 /**************************************************************************/
42 #include "tm_api.h"
43
44 /* Define the counters used in the demo application... */
45
46 unsigned long tm_interrupt_thread_0_counter;
47 unsigned long tm_interrupt_handler_counter;
48
49 /* Define the test thread prototypes. */
50
51 void tm_interrupt_thread_0_entry(void *p1, void *p2, void *p3);
52
53 /* Define the reporting function prototype. */
54
55 void tm_interrupt_thread_report(void);
56
57 /* Define the interrupt handler. This must be called from the RTOS. */
58
59 void tm_interrupt_handler(void);
60
61 /* Define the initialization prototype. */
62
63 void tm_interrupt_processing_initialize(void);
64
65 /* Define main entry point. */
66
main(void)67 int main(void)
68 {
69
70 /* Initialize the test. */
71 tm_initialize(tm_interrupt_processing_initialize);
72
73 return 0;
74 }
75
76 /* Define the interrupt processing test initialization. */
77
tm_interrupt_processing_initialize(void)78 void tm_interrupt_processing_initialize(void)
79 {
80
81 /* Create thread that generates the interrupt at priority 10. */
82 tm_thread_create(0, 10, tm_interrupt_thread_0_entry);
83
84 /*
85 * Create a semaphore that will be posted from the interrupt
86 * handler.
87 */
88 tm_semaphore_create(0);
89
90 /* Resume just thread 0. */
91 tm_thread_resume(0);
92
93 tm_interrupt_thread_report();
94 }
95
96 /* Define the thread that generates the interrupt. */
tm_interrupt_thread_0_entry(void * p1,void * p2,void * p3)97 void tm_interrupt_thread_0_entry(void *p1, void *p2, void *p3)
98 {
99
100 int status;
101
102 /* Pickup the semaphore since it is initialized to 1 by default. */
103 status = tm_semaphore_get(0);
104
105 /* Check for good status. */
106 if (status != TM_SUCCESS) {
107 return;
108 }
109
110 while (1) {
111
112 /*
113 * Force an interrupt. The underlying RTOS must see that the
114 * the interrupt handler is called from the appropriate software
115 * interrupt or trap.
116 */
117
118 TM_CAUSE_INTERRUPT;
119
120 /*
121 * We won't get back here until the interrupt processing is
122 * complete, including the setting of the semaphore from the
123 * interrupt handler.
124 */
125
126 /* Pickup the semaphore set by the interrupt handler. */
127 status = tm_semaphore_get(0);
128
129 /* Check for good status. */
130 if (status != TM_SUCCESS) {
131 return;
132 }
133
134 /* Increment this thread's counter. */
135 tm_interrupt_thread_0_counter++;
136 }
137 }
138
139 /*
140 * Define the interrupt handler. This must be called from the RTOS trap handler.
141 * To be fair, it must behave just like a processor interrupt, i.e. it must save
142 * the full context of the interrupted thread during the preemption processing.
143 */
tm_interrupt_handler(void)144 void tm_interrupt_handler(void)
145 {
146 /* Increment the interrupt count. */
147 tm_interrupt_handler_counter++;
148
149 /* Put the semaphore from the interrupt handler. */
150 tm_semaphore_put(0);
151 }
152
153 /* Define the interrupt test reporting function. */
tm_interrupt_thread_report(void)154 void tm_interrupt_thread_report(void)
155 {
156
157 unsigned long total;
158 unsigned long last_total;
159 unsigned long relative_time;
160 unsigned long average;
161
162 /* Initialize the last total. */
163 last_total = 0;
164
165 /* Initialize the relative time. */
166 relative_time = 0;
167
168 while (1) {
169
170 /* Sleep to allow the test to run. */
171 tm_thread_sleep(TM_TEST_DURATION);
172
173 /* Increment the relative time. */
174 relative_time = relative_time + TM_TEST_DURATION;
175
176 /* Print results to the stdio window. */
177 printf("**** Thread-Metric Interrupt Processing Test **** Relative Time: %lu\n",
178 relative_time);
179
180 /* Calculate the total of all the counters. */
181 total = tm_interrupt_thread_0_counter + tm_interrupt_handler_counter;
182
183 /* Calculate the average of all the counters. */
184 average = total / 2;
185
186 /* See if there are any errors. */
187 if ((tm_interrupt_thread_0_counter < (average - 1)) ||
188 (tm_interrupt_thread_0_counter > (average + 1)) ||
189 (tm_interrupt_handler_counter < (average - 1)) ||
190 (tm_interrupt_handler_counter > (average + 1))) {
191
192 printf("ERROR: Invalid counter value(s). Interrupt processing test has "
193 "failed!\n");
194 }
195
196 /* Show the total interrupts for the time period. */
197 printf("Time Period Total: %lu\n\n", tm_interrupt_handler_counter - last_total);
198
199 /* Save the last total number of interrupts. */
200 last_total = tm_interrupt_handler_counter;
201 }
202 }
203