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 /**   Preemptive Scheduling Test                                          */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 /**************************************************************************/
22 /*                                                                        */
23 /*  FUNCTION                                               RELEASE        */
24 /*                                                                        */
25 /*    tm_preemptive_scheduling_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 preemptive scheduling 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_preemptive_thread_0_counter;
47 unsigned long tm_preemptive_thread_1_counter;
48 unsigned long tm_preemptive_thread_2_counter;
49 unsigned long tm_preemptive_thread_3_counter;
50 unsigned long tm_preemptive_thread_4_counter;
51 
52 /* Define the test thread prototypes.  */
53 
54 void tm_preemptive_thread_0_entry(void *p1, void *p2, void *p3);
55 void tm_preemptive_thread_1_entry(void *p1, void *p2, void *p3);
56 void tm_preemptive_thread_2_entry(void *p1, void *p2, void *p3);
57 void tm_preemptive_thread_3_entry(void *p1, void *p2, void *p3);
58 void tm_preemptive_thread_4_entry(void *p1, void *p2, void *p3);
59 
60 /* Define the reporting function prototype.  */
61 
62 void tm_preemptive_thread_report(void);
63 
64 /* Define the initialization prototype.  */
65 
66 void tm_preemptive_scheduling_initialize(void);
67 
68 /* Define main entry point.  */
69 
main(void)70 int main(void)
71 {
72 
73 	/* Initialize the test.  */
74 	tm_initialize(tm_preemptive_scheduling_initialize);
75 
76 	return 0;
77 }
78 
79 /* Define the preemptive scheduling test initialization.  */
80 
tm_preemptive_scheduling_initialize(void)81 void tm_preemptive_scheduling_initialize(void)
82 {
83 
84 	/* Create thread 0 at priority 10.  */
85 	tm_thread_create(0, 10, tm_preemptive_thread_0_entry);
86 
87 	/* Create thread 1 at priority 9.  */
88 	tm_thread_create(1, 9, tm_preemptive_thread_1_entry);
89 
90 	/* Create thread 2 at priority 8.  */
91 	tm_thread_create(2, 8, tm_preemptive_thread_2_entry);
92 
93 	/* Create thread 3 at priority 7.  */
94 	tm_thread_create(3, 7, tm_preemptive_thread_3_entry);
95 
96 	/* Create thread 4 at priority 6.  */
97 	tm_thread_create(4, 6, tm_preemptive_thread_4_entry);
98 
99 	/* Resume just thread 0.  */
100 	tm_thread_resume(0);
101 
102 	tm_preemptive_thread_report();
103 }
104 
105 /* Define the first preemptive thread.  */
tm_preemptive_thread_0_entry(void * p1,void * p2,void * p3)106 void tm_preemptive_thread_0_entry(void *p1, void *p2, void *p3)
107 {
108 	(void)p1;
109 	(void)p2;
110 	(void)p3;
111 
112 	while (1) {
113 		/* Resume thread 1.  */
114 		tm_thread_resume(1);
115 
116 		/*
117 		 * We won't get back here until threads 1, 2, 3, and 4 all execute and
118 		 * self-suspend.
119 		 */
120 
121 		/* Increment this thread's counter.  */
122 		tm_preemptive_thread_0_counter++;
123 	}
124 }
125 
126 /* Define the second preemptive thread.  */
tm_preemptive_thread_1_entry(void * p1,void * p2,void * p3)127 void tm_preemptive_thread_1_entry(void *p1, void *p2, void *p3)
128 {
129 	(void)p1;
130 	(void)p2;
131 	(void)p3;
132 
133 	while (1) {
134 
135 		/* Resume thread 2.  */
136 		tm_thread_resume(2);
137 
138 		/*
139 		 * We won't get back here until threads 2, 3, and 4 all execute and
140 		 * self-suspend.
141 		 */
142 
143 		/* Increment this thread's counter.  */
144 		tm_preemptive_thread_1_counter++;
145 
146 		/* Suspend self!  */
147 		tm_thread_suspend(1);
148 	}
149 }
150 
151 /* Define the third preemptive thread.  */
tm_preemptive_thread_2_entry(void * p1,void * p2,void * p3)152 void tm_preemptive_thread_2_entry(void *p1, void *p2, void *p3)
153 {
154 	(void)p1;
155 	(void)p2;
156 	(void)p3;
157 
158 	while (1) {
159 
160 		/* Resume thread 3.  */
161 		tm_thread_resume(3);
162 
163 		/*
164 		 * We won't get back here until threads 3 and 4 execute and
165 		 * self-suspend.
166 		 */
167 
168 		/* Increment this thread's counter.  */
169 		tm_preemptive_thread_2_counter++;
170 
171 		/* Suspend self!  */
172 		tm_thread_suspend(2);
173 	}
174 }
175 
176 /* Define the fourth preemptive thread.  */
tm_preemptive_thread_3_entry(void * p1,void * p2,void * p3)177 void tm_preemptive_thread_3_entry(void *p1, void *p2, void *p3)
178 {
179 	(void)p1;
180 	(void)p2;
181 	(void)p3;
182 
183 	while (1) {
184 
185 		/* Resume thread 4.  */
186 		tm_thread_resume(4);
187 
188 		/*
189 		 * We won't get back here until thread 4 executes and
190 		 * self-suspends.
191 		 */
192 
193 		/* Increment this thread's counter.  */
194 		tm_preemptive_thread_3_counter++;
195 
196 		/* Suspend self!  */
197 		tm_thread_suspend(3);
198 	}
199 }
200 
201 /* Define the fifth preemptive thread.  */
tm_preemptive_thread_4_entry(void * p1,void * p2,void * p3)202 void tm_preemptive_thread_4_entry(void *p1, void *p2, void *p3)
203 {
204 	(void)p1;
205 	(void)p2;
206 	(void)p3;
207 
208 	while (1) {
209 
210 		/* Increment this thread's counter.  */
211 		tm_preemptive_thread_4_counter++;
212 
213 		/* Self suspend thread 4.  */
214 		tm_thread_suspend(4);
215 	}
216 }
217 
218 /* Define the preemptive test reporting function.  */
tm_preemptive_thread_report(void)219 void tm_preemptive_thread_report(void)
220 {
221 
222 	unsigned long total;
223 	unsigned long relative_time;
224 	unsigned long last_total;
225 	unsigned long average;
226 
227 	/* Initialize the last total.  */
228 	last_total = 0;
229 
230 	/* Initialize the relative time.  */
231 	relative_time = 0;
232 
233 	while (1) {
234 
235 		/* Sleep to allow the test to run.  */
236 		tm_thread_sleep(TM_TEST_DURATION);
237 
238 		/* Increment the relative time.  */
239 		relative_time = relative_time + TM_TEST_DURATION;
240 
241 		/* Print results to the stdio window.  */
242 		printf("**** Thread-Metric Preemptive Scheduling Test **** Relative Time: %lu\n",
243 		       relative_time);
244 
245 		/* Calculate the total of all the counters.  */
246 		total = tm_preemptive_thread_0_counter + tm_preemptive_thread_1_counter +
247 			tm_preemptive_thread_2_counter + tm_preemptive_thread_3_counter +
248 			tm_preemptive_thread_4_counter;
249 
250 		/* Calculate the average of all the counters.  */
251 		average = total / 5;
252 
253 		/* See if there are any errors.  */
254 		if ((tm_preemptive_thread_0_counter < (average - 1)) ||
255 		    (tm_preemptive_thread_0_counter > (average + 1)) ||
256 		    (tm_preemptive_thread_1_counter < (average - 1)) ||
257 		    (tm_preemptive_thread_1_counter > (average + 1)) ||
258 		    (tm_preemptive_thread_2_counter < (average - 1)) ||
259 		    (tm_preemptive_thread_2_counter > (average + 1)) ||
260 		    (tm_preemptive_thread_3_counter < (average - 1)) ||
261 		    (tm_preemptive_thread_3_counter > (average + 1)) ||
262 		    (tm_preemptive_thread_4_counter < (average - 1)) ||
263 		    (tm_preemptive_thread_4_counter > (average + 1))) {
264 
265 			printf("ERROR: Invalid counter value(s). Preemptive counters should not be "
266 			       "more that 1 different than the average!\n");
267 			printf("   Average: %lu, 0: %lu, 1: %lu, 2: %lu, 3: %lu, 4: %lu\n",
268 				average, tm_preemptive_thread_0_counter,
269 				tm_preemptive_thread_1_counter,
270 				tm_preemptive_thread_2_counter,
271 				tm_preemptive_thread_3_counter,
272 				tm_preemptive_thread_4_counter);
273 		}
274 
275 		/* Show the time period total.  */
276 		printf("Time Period Total:  %lu\n\n", total - last_total);
277 
278 		/* Save the last total.  */
279 		last_total = total;
280 	}
281 }
282