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