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