1 /* This is a small demo of the high-performance ThreadX kernel. It includes examples of eight
2 threads of different priorities, using a message queue, semaphore, mutex, event flags group,
3 byte pool, and block pool. */
4
5 #include "tx_api.h"
6 #include <stdio.h>
7
8 #define DEMO_STACK_SIZE 1024
9 #define DEMO_BYTE_POOL_SIZE 9120
10 #define DEMO_BLOCK_POOL_SIZE 100
11 #define DEMO_QUEUE_SIZE 100
12
13
14 /* Define the ThreadX object control blocks... */
15
16 TX_THREAD thread_0;
17 TX_THREAD thread_1;
18 TX_THREAD thread_2;
19 TX_THREAD thread_3;
20 TX_THREAD thread_4;
21 TX_THREAD thread_5;
22 TX_THREAD thread_6;
23 TX_THREAD thread_7;
24 TX_QUEUE queue_0;
25 TX_SEMAPHORE semaphore_0;
26 TX_MUTEX mutex_0;
27 TX_EVENT_FLAGS_GROUP event_flags_0;
28 TX_BYTE_POOL byte_pool_0;
29 TX_BLOCK_POOL block_pool_0;
30
31
32 /* Define the counters used in the demo application... */
33
34 ULONG thread_0_counter;
35 ULONG thread_1_counter;
36 ULONG thread_1_messages_sent;
37 ULONG thread_2_counter;
38 ULONG thread_2_messages_received;
39 ULONG thread_3_counter;
40 ULONG thread_4_counter;
41 ULONG thread_5_counter;
42 ULONG thread_6_counter;
43 ULONG thread_7_counter;
44
45
46 /* Define thread prototypes. */
47
48 void thread_0_entry(ULONG thread_input);
49 void thread_1_entry(ULONG thread_input);
50 void thread_2_entry(ULONG thread_input);
51 void thread_3_and_4_entry(ULONG thread_input);
52 void thread_5_entry(ULONG thread_input);
53 void thread_6_and_7_entry(ULONG thread_input);
54
55
56 /* Define main entry point. */
57
main()58 int main()
59 {
60
61 /* Enter the ThreadX kernel. */
62 tx_kernel_enter();
63 }
64
65
66 /* Define what the initial system looks like. */
67
tx_application_define(void * first_unused_memory)68 void tx_application_define(void *first_unused_memory)
69 {
70
71 CHAR *pointer = TX_NULL;
72
73
74 /* Create a byte memory pool from which to allocate the thread stacks. */
75 tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
76
77 /* Put system definition stuff in here, e.g. thread creates and other assorted
78 create information. */
79
80 /* Allocate the stack for thread 0. */
81 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
82
83 /* Create the main thread. */
84 tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
85 pointer, DEMO_STACK_SIZE,
86 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
87
88
89 /* Allocate the stack for thread 1. */
90 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
91
92 /* Create threads 1 and 2. These threads pass information through a ThreadX
93 message queue. It is also interesting to note that these threads have a time
94 slice. */
95 tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
96 pointer, DEMO_STACK_SIZE,
97 16, 16, 4, TX_AUTO_START);
98
99 /* Allocate the stack for thread 2. */
100 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
101
102 tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
103 pointer, DEMO_STACK_SIZE,
104 16, 16, 4, TX_AUTO_START);
105
106 /* Allocate the stack for thread 3. */
107 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
108
109 /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
110 An interesting thing here is that both threads share the same instruction area. */
111 tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
112 pointer, DEMO_STACK_SIZE,
113 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
114
115 /* Allocate the stack for thread 4. */
116 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
117
118 tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
119 pointer, DEMO_STACK_SIZE,
120 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
121
122 /* Allocate the stack for thread 5. */
123 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
124
125 /* Create thread 5. This thread simply pends on an event flag which will be set
126 by thread_0. */
127 tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
128 pointer, DEMO_STACK_SIZE,
129 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
130
131 /* Allocate the stack for thread 6. */
132 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
133
134 /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
135 tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
136 pointer, DEMO_STACK_SIZE,
137 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
138
139 /* Allocate the stack for thread 7. */
140 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
141
142 tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
143 pointer, DEMO_STACK_SIZE,
144 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
145
146 /* Allocate the message queue. */
147 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
148
149 /* Create the message queue shared by threads 1 and 2. */
150 tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
151
152 /* Create the semaphore used by threads 3 and 4. */
153 tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
154
155 /* Create the event flags group used by threads 1 and 5. */
156 tx_event_flags_create(&event_flags_0, "event flags 0");
157
158 /* Create the mutex used by thread 6 and 7 without priority inheritance. */
159 tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
160
161 /* Allocate the memory for a small block pool. */
162 tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
163
164 /* Create a block memory pool to allocate a message buffer from. */
165 tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
166
167 /* Allocate a block and release the block memory. */
168 tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
169
170 /* Release the block back to the pool. */
171 tx_block_release(pointer);
172 }
173
174
175
176 /* Define the test threads. */
177
thread_0_entry(ULONG thread_input)178 void thread_0_entry(ULONG thread_input)
179 {
180
181 UINT status;
182
183
184 /* This thread simply sits in while-forever-sleep loop. */
185 while(1)
186 {
187
188 /* Increment the thread counter. */
189 thread_0_counter++;
190
191 /* Print results. */
192 printf("**** ThreadX Win32 Demonstration **** (c) 1996-2020 Microsoft Corporation\n\n");
193 printf(" thread 0 events sent: %lu\n", thread_0_counter);
194 printf(" thread 1 messages sent: %lu\n", thread_1_counter);
195 printf(" thread 2 messages received: %lu\n", thread_2_counter);
196 printf(" thread 3 obtained semaphore: %lu\n", thread_3_counter);
197 printf(" thread 4 obtained semaphore: %lu\n", thread_4_counter);
198 printf(" thread 5 events received: %lu\n", thread_5_counter);
199 printf(" thread 6 mutex obtained: %lu\n", thread_6_counter);
200 printf(" thread 7 mutex obtained: %lu\n\n", thread_7_counter);
201
202 /* Sleep for 10 ticks. */
203 tx_thread_sleep(10);
204
205 /* Set event flag 0 to wakeup thread 5. */
206 status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
207
208 /* Check status. */
209 if (status != TX_SUCCESS)
210 break;
211 }
212 }
213
214
thread_1_entry(ULONG thread_input)215 void thread_1_entry(ULONG thread_input)
216 {
217
218 UINT status;
219
220
221 /* This thread simply sends messages to a queue shared by thread 2. */
222 while(1)
223 {
224
225 /* Increment the thread counter. */
226 thread_1_counter++;
227
228 /* Send message to queue 0. */
229 status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
230
231 /* Check completion status. */
232 if (status != TX_SUCCESS)
233 break;
234
235 /* Increment the message sent. */
236 thread_1_messages_sent++;
237 }
238 }
239
240
thread_2_entry(ULONG thread_input)241 void thread_2_entry(ULONG thread_input)
242 {
243
244 ULONG received_message;
245 UINT status;
246
247 /* This thread retrieves messages placed on the queue by thread 1. */
248 while(1)
249 {
250
251 /* Increment the thread counter. */
252 thread_2_counter++;
253
254 /* Retrieve a message from the queue. */
255 status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
256
257 /* Check completion status and make sure the message is what we
258 expected. */
259 if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
260 break;
261
262 /* Otherwise, all is okay. Increment the received message count. */
263 thread_2_messages_received++;
264 }
265 }
266
267
thread_3_and_4_entry(ULONG thread_input)268 void thread_3_and_4_entry(ULONG thread_input)
269 {
270
271 UINT status;
272
273
274 /* This function is executed from thread 3 and thread 4. As the loop
275 below shows, these function compete for ownership of semaphore_0. */
276 while(1)
277 {
278
279 /* Increment the thread counter. */
280 if (thread_input == 3)
281 thread_3_counter++;
282 else
283 thread_4_counter++;
284
285 /* Get the semaphore with suspension. */
286 status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
287
288 /* Check status. */
289 if (status != TX_SUCCESS)
290 break;
291
292 /* Sleep for 2 ticks to hold the semaphore. */
293 tx_thread_sleep(2);
294
295 /* Release the semaphore. */
296 status = tx_semaphore_put(&semaphore_0);
297
298 /* Check status. */
299 if (status != TX_SUCCESS)
300 break;
301 }
302 }
303
304
thread_5_entry(ULONG thread_input)305 void thread_5_entry(ULONG thread_input)
306 {
307
308 UINT status;
309 ULONG actual_flags;
310
311
312 /* This thread simply waits for an event in a forever loop. */
313 while(1)
314 {
315
316 /* Increment the thread counter. */
317 thread_5_counter++;
318
319 /* Wait for event flag 0. */
320 status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
321 &actual_flags, TX_WAIT_FOREVER);
322
323 /* Check status. */
324 if ((status != TX_SUCCESS) || (actual_flags != 0x1))
325 break;
326 }
327 }
328
329
thread_6_and_7_entry(ULONG thread_input)330 void thread_6_and_7_entry(ULONG thread_input)
331 {
332
333 UINT status;
334
335
336 /* This function is executed from thread 6 and thread 7. As the loop
337 below shows, these function compete for ownership of mutex_0. */
338 while(1)
339 {
340
341 /* Increment the thread counter. */
342 if (thread_input == 6)
343 thread_6_counter++;
344 else
345 thread_7_counter++;
346
347 /* Get the mutex with suspension. */
348 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
349
350 /* Check status. */
351 if (status != TX_SUCCESS)
352 break;
353
354 /* Get the mutex again with suspension. This shows
355 that an owning thread may retrieve the mutex it
356 owns multiple times. */
357 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
358
359 /* Check status. */
360 if (status != TX_SUCCESS)
361 break;
362
363 /* Sleep for 2 ticks to hold the mutex. */
364 tx_thread_sleep(2);
365
366 /* Release the mutex. */
367 status = tx_mutex_put(&mutex_0);
368
369 /* Check status. */
370 if (status != TX_SUCCESS)
371 break;
372
373 /* Release the mutex again. This will actually
374 release ownership since it was obtained twice. */
375 status = tx_mutex_put(&mutex_0);
376
377 /* Check status. */
378 if (status != TX_SUCCESS)
379 break;
380 }
381 }
382