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