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