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 "board_setup.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 TraceX trace oblects */
15 #define TRACE_BUFFER_SIZE (4 * 1024)
16 #define TRACE_OBJECTS_COUNT 20
17 /* Define TraceX trace buffer */
18 UCHAR tx_trace_buffer[TRACE_BUFFER_SIZE];
19
20
21 /* Define the ThreadX object control blocks... */
22
23 TX_THREAD thread_0;
24 TX_THREAD thread_1;
25 TX_THREAD thread_2;
26 TX_THREAD thread_3;
27 TX_THREAD thread_4;
28 TX_THREAD thread_5;
29 TX_THREAD thread_6;
30 TX_THREAD thread_7;
31 TX_QUEUE queue_0;
32 TX_SEMAPHORE semaphore_0;
33 TX_MUTEX mutex_0;
34 TX_EVENT_FLAGS_GROUP event_flags_0;
35 TX_BYTE_POOL byte_pool_0;
36 TX_BLOCK_POOL block_pool_0;
37
38
39 /* Define demo timer */
40 #define DEMO_TIMER_PERIOD 10
41 #define DEMO_TIMER_VALUE 0xaaaaaaaa
42 TX_TIMER timer_0;
43 ULONG timer_0_counter;
44
45
46 /* Define the counters used in the demo application... */
47
48 ULONG thread_0_counter;
49 ULONG thread_1_counter;
50 ULONG thread_1_messages_sent;
51 ULONG thread_2_counter;
52 ULONG thread_2_messages_received;
53 ULONG thread_3_counter;
54 ULONG thread_4_counter;
55 ULONG thread_5_counter;
56 ULONG thread_6_counter;
57 ULONG thread_7_counter;
58
59
60 /* Define thread prototypes. */
61
62 void thread_0_entry(ULONG thread_input);
63 void thread_1_entry(ULONG thread_input);
64 void thread_2_entry(ULONG thread_input);
65 void thread_3_and_4_entry(ULONG thread_input);
66 void thread_5_entry(ULONG thread_input);
67 void thread_6_and_7_entry(ULONG thread_input);
68 void my_stack_error_handler(TX_THREAD *thread_ptr);
69 void my_timer_function(ULONG timer_input);
70
71
72 /* Define main entry point. */
73
main()74 void main()
75 {
76 /* Setup the hardware. */
77 hardware_setup();
78
79 /* Enter the ThreadX kernel. */
80 tx_kernel_enter();
81 }
82
83
84 /* Define what the initial system looks like. */
85
tx_application_define(void * first_unused_memory)86 void tx_application_define(void *first_unused_memory)
87 {
88
89 CHAR *pointer = TX_NULL;
90 UINT status;
91
92 /* Enable event tracing using the global �trace_buffer� memory and supporting
93 a maximum of TRACE_OBJECTS_COUNT ThreadX objects in the registry. */
94 if ((status = tx_trace_enable(tx_trace_buffer, TRACE_BUFFER_SIZE, TRACE_OBJECTS_COUNT)) != TX_SUCCESS)
95 {
96 while (1);
97 }
98
99 /* Register thread stack error notification callback */
100 if ((status = tx_thread_stack_error_notify(my_stack_error_handler)) != TX_SUCCESS)
101 {
102 while (1);
103 }
104
105 /* Create a byte memory pool from which to allocate the thread stacks. */
106 status = tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
107 if (status != TX_SUCCESS)
108 {
109 while (1);
110 }
111
112 /* Put system definition stuff in here, e.g. thread creates and other assorted
113 create information. */
114
115 /* Allocate the stack for thread 0. */
116 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
117 if (status != TX_SUCCESS)
118 {
119 while (1);
120 }
121
122 /* Create the main thread. */
123 status = tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
124 pointer, DEMO_STACK_SIZE,
125 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
126 if (status != TX_SUCCESS)
127 {
128 while (1);
129 }
130
131 /* Allocate the stack for thread 1. */
132 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
133 if (status != TX_SUCCESS)
134 {
135 while (1);
136 }
137
138 /* Create threads 1 and 2. These threads pass information through a ThreadX
139 message queue. It is also interesting to note that these threads have a time
140 slice. */
141 status = tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
142 pointer, DEMO_STACK_SIZE,
143 16, 16, 4, TX_AUTO_START);
144 if (status != TX_SUCCESS)
145 {
146 while (1);
147 }
148
149 /* Allocate the stack for thread 2. */
150 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
151 if (status != TX_SUCCESS)
152 {
153 while (1);
154 }
155
156 status = tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
157 pointer, DEMO_STACK_SIZE,
158 16, 16, 4, TX_AUTO_START);
159 if (status != TX_SUCCESS)
160 {
161 while (1);
162 }
163
164 /* Allocate the stack for thread 3. */
165 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
166 if (status != TX_SUCCESS)
167 {
168 while (1);
169 }
170
171 /* Create threads 3 and 4. These threads compete for a ThreadX counting semaphore.
172 An interesting thing here is that both threads share the same instruction area. */
173 status = tx_thread_create(&thread_3, "thread 3", thread_3_and_4_entry, 3,
174 pointer, DEMO_STACK_SIZE,
175 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
176 if (status != TX_SUCCESS)
177 {
178 while (1);
179 }
180
181 /* Allocate the stack for thread 4. */
182 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
183 if (status != TX_SUCCESS)
184 {
185 while (1);
186 }
187
188 status = tx_thread_create(&thread_4, "thread 4", thread_3_and_4_entry, 4,
189 pointer, DEMO_STACK_SIZE,
190 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
191 if (status != TX_SUCCESS)
192 {
193 while (1);
194 }
195
196 /* Allocate the stack for thread 5. */
197 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
198 if (status != TX_SUCCESS)
199 {
200 while (1);
201 }
202
203 /* Create thread 5. This thread simply pends on an event flag which will be set
204 by thread_0. */
205 status = tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
206 pointer, DEMO_STACK_SIZE,
207 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
208 if (status != TX_SUCCESS)
209 {
210 while (1);
211 }
212
213 /* Allocate the stack for thread 6. */
214 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
215 if (status != TX_SUCCESS)
216 {
217 while (1);
218 }
219
220 /* Create threads 6 and 7. These threads compete for a ThreadX mutex. */
221 status = tx_thread_create(&thread_6, "thread 6", thread_6_and_7_entry, 6,
222 pointer, DEMO_STACK_SIZE,
223 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
224 if (status != TX_SUCCESS)
225 {
226 while (1);
227 }
228
229 /* Allocate the stack for thread 7. */
230 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
231 if (status != TX_SUCCESS)
232 {
233 while (1);
234 }
235
236 status = tx_thread_create(&thread_7, "thread 7", thread_6_and_7_entry, 7,
237 pointer, DEMO_STACK_SIZE,
238 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
239 if (status != TX_SUCCESS)
240 {
241 while (1);
242 }
243
244 /* Allocate the message queue. */
245 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_QUEUE_SIZE*sizeof(ULONG), TX_NO_WAIT);
246 if (status != TX_SUCCESS)
247 {
248 while (1);
249 }
250
251 /* Create the message queue shared by threads 1 and 2. */
252 status = tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, pointer, DEMO_QUEUE_SIZE*sizeof(ULONG));
253 if (status != TX_SUCCESS)
254 {
255 while (1);
256 }
257
258 /* Create the semaphore used by threads 3 and 4. */
259 status = tx_semaphore_create(&semaphore_0, "semaphore 0", 1);
260 if (status != TX_SUCCESS)
261 {
262 while (1);
263 }
264
265 /* Create the event flags group used by threads 1 and 5. */
266 status = tx_event_flags_create(&event_flags_0, "event flags 0");
267 if (status != TX_SUCCESS)
268 {
269 while (1);
270 }
271
272 /* Create the mutex used by thread 6 and 7 without priority inheritance. */
273 status = tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
274 if (status != TX_SUCCESS)
275 {
276 while (1);
277 }
278
279 /* Allocate the memory for a small block pool. */
280 status = tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_BLOCK_POOL_SIZE, TX_NO_WAIT);
281 if (status != TX_SUCCESS)
282 {
283 while (1);
284 }
285
286 /* Create a block memory pool to allocate a message buffer from. */
287 status = tx_block_pool_create(&block_pool_0, "block pool 0", sizeof(ULONG), pointer, DEMO_BLOCK_POOL_SIZE);
288 if (status != TX_SUCCESS)
289 {
290 while (1);
291 }
292
293 /* Allocate a block and release the block memory. */
294 status = tx_block_allocate(&block_pool_0, (VOID **) &pointer, TX_NO_WAIT);
295 if (status != TX_SUCCESS)
296 {
297 while (1);
298 }
299
300 /* Release the block back to the pool. */
301 status = tx_block_release(pointer);
302 if (status != TX_SUCCESS)
303 {
304 while (1);
305 }
306
307 /* Create the periodic timer. */
308 status = tx_timer_create(&timer_0, "timer 0", my_timer_function, (ULONG) DEMO_TIMER_VALUE, DEMO_TIMER_PERIOD, DEMO_TIMER_PERIOD, TX_AUTO_ACTIVATE);
309 if (status != TX_SUCCESS)
310 {
311 while (1);
312 }
313 }
314
315
316
317 /* Define the test threads. */
318
thread_0_entry(ULONG thread_input)319 void thread_0_entry(ULONG thread_input)
320 {
321
322 UINT status;
323
324
325 /* This thread simply sits in while-forever-sleep loop. */
326 while(1)
327 {
328
329 /* Increment the thread counter. */
330 thread_0_counter++;
331
332 /* Sleep for 10 ticks. */
333 tx_thread_sleep(10);
334
335 /* Set event flag 0 to wakeup thread 5. */
336 status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
337
338 /* Check status. */
339 if (status != TX_SUCCESS)
340 break;
341 }
342 }
343
344
thread_1_entry(ULONG thread_input)345 void thread_1_entry(ULONG thread_input)
346 {
347
348 UINT status;
349
350
351 /* This thread simply sends messages to a queue shared by thread 2. */
352 while(1)
353 {
354
355 /* Increment the thread counter. */
356 thread_1_counter++;
357
358 /* Send message to queue 0. */
359 status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
360
361 /* Check completion status. */
362 if (status != TX_SUCCESS)
363 break;
364
365 /* Increment the message sent. */
366 thread_1_messages_sent++;
367 }
368 }
369
370
thread_2_entry(ULONG thread_input)371 void thread_2_entry(ULONG thread_input)
372 {
373
374 ULONG received_message;
375 UINT status;
376
377 /* This thread retrieves messages placed on the queue by thread 1. */
378 while(1)
379 {
380
381 /* Increment the thread counter. */
382 thread_2_counter++;
383
384 /* Retrieve a message from the queue. */
385 status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
386
387 /* Check completion status and make sure the message is what we
388 expected. */
389 if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
390 break;
391
392 /* Otherwise, all is okay. Increment the received message count. */
393 thread_2_messages_received++;
394 }
395 }
396
397
thread_3_and_4_entry(ULONG thread_input)398 void thread_3_and_4_entry(ULONG thread_input)
399 {
400
401 UINT status;
402
403
404 /* This function is executed from thread 3 and thread 4. As the loop
405 below shows, these function compete for ownership of semaphore_0. */
406 while(1)
407 {
408
409 /* Increment the thread counter. */
410 if (thread_input == 3)
411 thread_3_counter++;
412 else
413 thread_4_counter++;
414
415 /* Get the semaphore with suspension. */
416 status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
417
418 /* Check status. */
419 if (status != TX_SUCCESS)
420 break;
421
422 /* Sleep for 2 ticks to hold the semaphore. */
423 tx_thread_sleep(2);
424
425 /* Release the semaphore. */
426 status = tx_semaphore_put(&semaphore_0);
427
428 /* Check status. */
429 if (status != TX_SUCCESS)
430 break;
431 }
432 }
433
434
thread_5_entry(ULONG thread_input)435 void thread_5_entry(ULONG thread_input)
436 {
437
438 UINT status;
439 ULONG actual_flags;
440
441
442 /* This thread simply waits for an event in a forever loop. */
443 while(1)
444 {
445
446 /* Increment the thread counter. */
447 thread_5_counter++;
448
449 /* Wait for event flag 0. */
450 status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
451 &actual_flags, TX_WAIT_FOREVER);
452
453 /* Check status. */
454 if ((status != TX_SUCCESS) || (actual_flags != 0x1))
455 break;
456 }
457 }
458
459
thread_6_and_7_entry(ULONG thread_input)460 void thread_6_and_7_entry(ULONG thread_input)
461 {
462
463 UINT status;
464
465
466 /* This function is executed from thread 6 and thread 7. As the loop
467 below shows, these function compete for ownership of mutex_0. */
468 while(1)
469 {
470
471 /* Increment the thread counter. */
472 if (thread_input == 6)
473 thread_6_counter++;
474 else
475 thread_7_counter++;
476
477 /* Get the mutex with suspension. */
478 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
479
480 /* Check status. */
481 if (status != TX_SUCCESS)
482 break;
483
484 /* Get the mutex again with suspension. This shows
485 that an owning thread may retrieve the mutex it
486 owns multiple times. */
487 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
488
489 /* Check status. */
490 if (status != TX_SUCCESS)
491 break;
492
493 /* Sleep for 2 ticks to hold the mutex. */
494 tx_thread_sleep(2);
495
496 /* Release the mutex. */
497 status = tx_mutex_put(&mutex_0);
498
499 /* Check status. */
500 if (status != TX_SUCCESS)
501 break;
502
503 /* Release the mutex again. This will actually
504 release ownership since it was obtained twice. */
505 status = tx_mutex_put(&mutex_0);
506
507 /* Check status. */
508 if (status != TX_SUCCESS)
509 break;
510 }
511 }
512
513
my_stack_error_handler(TX_THREAD * thread_ptr)514 void my_stack_error_handler(TX_THREAD *thread_ptr)
515 {
516 while(1);
517 }
518
519
my_timer_function(ULONG timer_input)520 void my_timer_function(ULONG timer_input)
521 {
522 /* Increment the thread counter. */
523 timer_0_counter++;
524
525 if (timer_input != DEMO_TIMER_VALUE)
526 while(1);
527 }
528
529