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 the counters used in the demo application... */
32
33 ULONG thread_0_counter;
34 ULONG thread_1_counter;
35 ULONG thread_1_messages_sent;
36 ULONG thread_2_counter;
37 ULONG thread_2_messages_received;
38 ULONG thread_3_counter;
39 ULONG thread_4_counter;
40 ULONG thread_5_counter;
41 ULONG thread_6_counter;
42 ULONG thread_7_counter;
43
44
45 /* Define thread prototypes. */
46
47 void thread_0_entry(ULONG thread_input);
48 void thread_1_entry(ULONG thread_input);
49 void thread_2_entry(ULONG thread_input);
50 void thread_3_and_4_entry(ULONG thread_input);
51 void thread_5_entry(ULONG thread_input);
52 void thread_6_and_7_entry(ULONG thread_input);
53
54
55 /* Define main entry point. */
56
main()57 int main()
58 {
59
60 /* Enter the ThreadX kernel. */
61 tx_kernel_enter();
62 }
63
64
65 /* Define what the initial system looks like. */
66
tx_application_define(void * first_unused_memory)67 void tx_application_define(void *first_unused_memory)
68 {
69
70 CHAR *pointer = TX_NULL;
71
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 /* Sleep for 10 ticks. */
191 tx_thread_sleep(10);
192
193 /* Set event flag 0 to wakeup thread 5. */
194 status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
195
196 /* Check status. */
197 if (status != TX_SUCCESS)
198 break;
199 }
200 }
201
202
thread_1_entry(ULONG thread_input)203 void thread_1_entry(ULONG thread_input)
204 {
205
206 UINT status;
207
208
209 /* This thread simply sends messages to a queue shared by thread 2. */
210 while(1)
211 {
212
213 /* Increment the thread counter. */
214 thread_1_counter++;
215
216 /* Send message to queue 0. */
217 status = tx_queue_send(&queue_0, &thread_1_messages_sent, TX_WAIT_FOREVER);
218
219 /* Check completion status. */
220 if (status != TX_SUCCESS)
221 break;
222
223 /* Increment the message sent. */
224 thread_1_messages_sent++;
225 }
226 }
227
228
thread_2_entry(ULONG thread_input)229 void thread_2_entry(ULONG thread_input)
230 {
231
232 ULONG received_message;
233 UINT status;
234
235 /* This thread retrieves messages placed on the queue by thread 1. */
236 while(1)
237 {
238
239 /* Increment the thread counter. */
240 thread_2_counter++;
241
242 /* Retrieve a message from the queue. */
243 status = tx_queue_receive(&queue_0, &received_message, TX_WAIT_FOREVER);
244
245 /* Check completion status and make sure the message is what we
246 expected. */
247 if ((status != TX_SUCCESS) || (received_message != thread_2_messages_received))
248 break;
249
250 /* Otherwise, all is okay. Increment the received message count. */
251 thread_2_messages_received++;
252 }
253 }
254
255
thread_3_and_4_entry(ULONG thread_input)256 void thread_3_and_4_entry(ULONG thread_input)
257 {
258
259 UINT status;
260
261
262 /* This function is executed from thread 3 and thread 4. As the loop
263 below shows, these function compete for ownership of semaphore_0. */
264 while(1)
265 {
266
267 /* Increment the thread counter. */
268 if (thread_input == 3)
269 thread_3_counter++;
270 else
271 thread_4_counter++;
272
273 /* Get the semaphore with suspension. */
274 status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER);
275
276 /* Check status. */
277 if (status != TX_SUCCESS)
278 break;
279
280 /* Sleep for 2 ticks to hold the semaphore. */
281 tx_thread_sleep(2);
282
283 /* Release the semaphore. */
284 status = tx_semaphore_put(&semaphore_0);
285
286 /* Check status. */
287 if (status != TX_SUCCESS)
288 break;
289 }
290 }
291
292
thread_5_entry(ULONG thread_input)293 void thread_5_entry(ULONG thread_input)
294 {
295
296 UINT status;
297 ULONG actual_flags;
298
299
300 /* This thread simply waits for an event in a forever loop. */
301 while(1)
302 {
303
304 /* Increment the thread counter. */
305 thread_5_counter++;
306
307 /* Wait for event flag 0. */
308 status = tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
309 &actual_flags, TX_WAIT_FOREVER);
310
311 /* Check status. */
312 if ((status != TX_SUCCESS) || (actual_flags != 0x1))
313 break;
314 }
315 }
316
317
thread_6_and_7_entry(ULONG thread_input)318 void thread_6_and_7_entry(ULONG thread_input)
319 {
320
321 UINT status;
322
323
324 /* This function is executed from thread 6 and thread 7. As the loop
325 below shows, these function compete for ownership of mutex_0. */
326 while(1)
327 {
328
329 /* Increment the thread counter. */
330 if (thread_input == 6)
331 thread_6_counter++;
332 else
333 thread_7_counter++;
334
335 /* Get the mutex with suspension. */
336 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
337
338 /* Check status. */
339 if (status != TX_SUCCESS)
340 break;
341
342 /* Get the mutex again with suspension. This shows
343 that an owning thread may retrieve the mutex it
344 owns multiple times. */
345 status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
346
347 /* Check status. */
348 if (status != TX_SUCCESS)
349 break;
350
351 /* Sleep for 2 ticks to hold the mutex. */
352 tx_thread_sleep(2);
353
354 /* Release the mutex. */
355 status = tx_mutex_put(&mutex_0);
356
357 /* Check status. */
358 if (status != TX_SUCCESS)
359 break;
360
361 /* Release the mutex again. This will actually
362 release ownership since it was obtained twice. */
363 status = tx_mutex_put(&mutex_0);
364
365 /* Check status. */
366 if (status != TX_SUCCESS)
367 break;
368 }
369 }
370