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