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