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