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