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