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