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