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