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