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