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