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