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