1 /* This test is designed to test the mutex suspension and timeout functionality.  */
2 
3 #include   <stdio.h>
4 #include   "tx_api.h"
5 #include   "tx_thread.h"
6 #include   "tx_mutex.h"
7 
8 
9 //static unsigned long   thread_0_counter =  0;
10 static TX_THREAD       thread_0;
11 static TX_THREAD       thread_1;
12 static TX_THREAD       thread_2;
13 static TX_THREAD       thread_3;
14 static TX_THREAD       thread_4;
15 static TX_THREAD       low_priority;
16 
17 
18 static TX_MUTEX        mutex_0;
19 static TX_MUTEX        mutex_1;
20 extern UINT            mutex_priority_change_extension_selection;
21 
22 
23 /* Define thread prototypes.  */
24 
25 static void    thread_0_entry(ULONG thread_input);
26 static void    thread_1_entry(ULONG thread_input);
27 static void    thread_2_entry(ULONG thread_input);
28 static void    thread_3_entry(ULONG thread_input);
29 static void    thread_4_entry(ULONG thread_input);
30 static void    low_priority_entry(ULONG thread_input);
31 
32 
33 /* Prototype for test control return.  */
34 extern void  test_control_return(UINT status);
35 
36 
37 #ifndef TX_MANUAL_TEST
38 
39 /* Define test flags for automated test.  */
40 
41 extern TEST_FLAG    threadx_mutex_suspension_put_test;
42 extern TEST_FLAG    threadx_mutex_suspension_priority_test;
43 
44 #endif
45 
46 
47 /* This test routine is used to get NULL suspension lists in various parts of tx_mutex_put.  This is hooked up to IRQ 0 on this simulation and is entered manually at the
48    correct time.  */
abort_all_threads_suspended_on_mutex(void)49 void  abort_all_threads_suspended_on_mutex(void)
50 {
51 
52 TX_THREAD       *thread_ptr;
53 
54     thread_ptr =  _tx_thread_created_ptr;
55     while (thread_ptr)
56     {
57        if (thread_ptr -> tx_thread_state == TX_MUTEX_SUSP)
58            tx_thread_wait_abort(thread_ptr);
59 
60        thread_ptr =  thread_ptr -> tx_thread_created_next;
61        if (thread_ptr == _tx_thread_created_ptr)
62             break;
63     }
64 }
65 
66 
67 /* This test routine is used to get a thread of a non ready state into _tx_mutex_change, called froim _tx_mutex_put.  This is hooked up to IRQ 1 on this simulation and is entered manually at the
68    correct time.  */
suspend_lowest_priority(void)69 void  suspend_lowest_priority(void)
70 {
71 
72 TX_INTERRUPT_SAVE_AREA
73 
74 TX_THREAD   *thread_ptr;
75 
76 
77     /* Determine which extension to perform...   to get to the different error checks in _tx_mutex_priority_change.  */
78     if (mutex_priority_change_extension_selection == 0)
79     {
80 
81         /* Setup the thread pointer.  */
82         thread_ptr =  &thread_0;
83 
84         /* Disable interrupts.  */
85         TX_DISABLE
86 
87         /* Set the state to suspended.  */
88         thread_ptr -> tx_thread_state =    TX_SUSPENDED;
89 
90 #ifdef TX_NOT_INTERRUPTABLE
91 
92         /* Call actual non-interruptable thread suspension routine.  */
93         _tx_thread_system_ni_suspend(thread_ptr, ((ULONG) 0));
94 
95         /* Restore interrupts.  */
96         TX_RESTORE
97 #else
98 
99         /* Set the suspending flag. */
100         thread_ptr -> tx_thread_suspending =  TX_TRUE;
101 
102         /* Setup for no timeout period.  */
103         thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  ((ULONG) 0);
104 
105         /* Temporarily disable preemption.  */
106         _tx_thread_preempt_disable++;
107 
108         /* Restore interrupts.  */
109         TX_RESTORE
110 
111         /* Call actual thread suspension routine.  */
112         _tx_thread_system_suspend(thread_ptr);
113 #endif
114     }
115     else if (mutex_priority_change_extension_selection == 1)
116     {
117 
118         /* Make the mapped core field to be invalid to exercise the error checking branch for core_index.  */
119         thread_0.tx_thread_smp_core_mapped =  TX_THREAD_SMP_MAX_CORES;
120     }
121 }
122 
123 
124 /* Define what the initial system looks like.  */
125 
126 #ifdef CTEST
test_application_define(void * first_unused_memory)127 void test_application_define(void *first_unused_memory)
128 #else
129 void    threadx_mutex_suspension_timeout_application_define(void *first_unused_memory)
130 #endif
131 {
132 
133 UINT    status;
134 CHAR    *pointer;
135 
136 
137     /* Put first available memory address into a character pointer.  */
138     pointer =  (CHAR *) first_unused_memory;
139 
140     /* Put system definition stuff in here, e.g. thread creates and other assorted
141        create information.  */
142 
143     status =  tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
144             pointer, TEST_STACK_SIZE_PRINTF,
145             16, 16, 100, TX_AUTO_START);
146     pointer = pointer + TEST_STACK_SIZE_PRINTF;
147     status +=  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
148             pointer, TEST_STACK_SIZE_PRINTF,
149             1, 1, 100, TX_DONT_START);
150     pointer = pointer + TEST_STACK_SIZE_PRINTF;
151     status +=  tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
152             pointer, TEST_STACK_SIZE_PRINTF,
153             2, 2, 100, TX_DONT_START);
154     pointer = pointer + TEST_STACK_SIZE_PRINTF;
155     status +=  tx_thread_create(&thread_3, "thread 3", thread_3_entry, 3,
156             pointer, TEST_STACK_SIZE_PRINTF,
157             3, 3, 100, TX_DONT_START);
158     pointer = pointer + TEST_STACK_SIZE_PRINTF;
159     status +=  tx_thread_create(&thread_4, "thread 4", thread_4_entry, 4,
160             pointer, TEST_STACK_SIZE_PRINTF,
161             4, 4, 100, TX_DONT_START);
162     pointer = pointer + TEST_STACK_SIZE_PRINTF;
163     status +=  tx_thread_create(&low_priority, "low priority", low_priority_entry, 30,
164             pointer, TEST_STACK_SIZE_PRINTF,
165             30, 30, 100, TX_DONT_START);
166     pointer = pointer + TEST_STACK_SIZE_PRINTF;
167 
168     /* Check for status.  */
169     if (status != TX_SUCCESS)
170     {
171 
172         printf("Running Mutex Suspension Timeout Test............................... ERROR #1\n");
173         test_control_return(1);
174     }
175 
176     /* Create mutexes.  */
177     status =  tx_mutex_create(&mutex_0, "mutex 0", TX_NO_INHERIT);
178     status += tx_mutex_create(&mutex_1, "mutex 1", TX_INHERIT);
179 
180     /* Check for status.  */
181     if (status != TX_SUCCESS)
182     {
183 
184         printf("Running Mutex Suspension Timeout Test............................... ERROR #2\n");
185         test_control_return(1);
186     }
187 
188     /* Get the mutex to prevent thread from getting it.  */
189     tx_mutex_get(&mutex_0, TX_NO_WAIT);
190 }
191 
192 
193 
194 /* Define the test threads.  */
195 
thread_0_entry(ULONG thread_input)196 static void    thread_0_entry(ULONG thread_input)
197 {
198 
199 TX_INTERRUPT_SAVE_AREA
200 
201 TX_THREAD   *temp_thread;
202 UINT        status;
203 
204 
205     /* Inform user.  */
206     printf("Running Mutex Suspension Timeout Test............................... ");
207 
208     /* Sleep for 2 ticks for fresh timer.  */
209     tx_thread_sleep(2);
210 
211     /* Set clock to 0.  */
212     tx_time_set(0);
213 
214     /* Suspend on the mutex. */
215     status =  tx_mutex_get(&mutex_0, 33);
216 
217     /* Did we get the right status at the right time?  */
218     if ((status != TX_NOT_AVAILABLE) || (tx_time_get() != 33))
219     {
220 
221         /* Mutex error.  */
222         printf("ERROR #3\n");
223         test_control_return(1);
224     }
225 
226     /* Get the mutex.  */
227      status =  tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
228 
229      /* Make sure the three higher priority threads suspend on the mutex.  */
230      tx_thread_resume(&thread_4);
231      tx_thread_resume(&thread_3);
232      tx_thread_resume(&thread_2);
233      tx_thread_resume(&thread_1);
234 
235 
236 #ifdef TX_MANUAL_TEST
237 
238      /* Set BP hear and step into code and generate appropriate interrupt IRQ 0 by hand right after the prioritize function with interrupts enabled. This is to achieve the empty list branch coverage after the prioritize function. */
239      tx_mutex_put(&mutex_1);
240 #else
241 
242      /* Set the flag such that generate the condition wehre the empty list condition is satisfied in the branch coverage.  */
243      threadx_mutex_suspension_put_test =  1;
244      tx_mutex_put(&mutex_1);
245 #endif
246 
247      /* Now some hand testing for tx_mutex_priority_change.  */
248 
249      /* Resume the low priority thread.  */
250      tx_thread_resume(&low_priority);
251 
252 	 /* Disable interrupts.  */
253 	 TX_DISABLE
254 
255      /* Simulate a call from inside of mutex put, but doing it here makes life easier.  */
256      _tx_thread_preempt_disable++;
257 
258 	 /* Move the current thread to a lower priority.  */
259 	 _tx_mutex_priority_change(&thread_0, 15);
260 	 _tx_mutex_priority_change(&thread_0, 16);
261 
262 	 /* Move the lower priority thread to a higher priority.  */
263 	 _tx_mutex_priority_change(&low_priority, 28);
264 	 _tx_mutex_priority_change(&low_priority, 29);
265 	 _tx_mutex_priority_change(&low_priority, 30);
266 
267      /* Change the priority of the current thread, such that we should have reverse the preemption-threshold issue.  */
268 	 thread_0.tx_thread_user_priority =  30;
269 	 thread_0.tx_thread_user_preempt_threshold =  30;
270      _tx_mutex_priority_change(&thread_0, 30);
271 
272      /* Change to an even lower priority.  */
273 	 thread_0.tx_thread_user_priority =  31;
274 	 thread_0.tx_thread_user_preempt_threshold =  31;
275      _tx_mutex_priority_change(&thread_0, 31);
276 
277 	 /* Move back to a higher-priority.  */
278 	 thread_0.tx_thread_user_priority =  30;
279 	 thread_0.tx_thread_user_preempt_threshold =  30;
280 	 _tx_mutex_priority_change(&thread_0, 16);
281 
282 #ifdef TX_MANUAL_TEST
283 
284      /* Set BP here and step into code and step through the code until the internal thread resume function returns, then issue an IRQ 1 to cause an ISR to suspend the thread and test the first condition.  */
285      _tx_mutex_priority_change(&thread_0, 30);
286 #else
287 
288      /* Set the flag to suspend the thread and test the first condition after internal resume is called.  */
289      mutex_priority_change_extension_selection =  0;
290      threadx_mutex_suspension_priority_test =  1;
291      _tx_mutex_priority_change(&thread_0, 30);
292 #endif
293 
294      /* Resume this thread.  */
295      tx_thread_resume(&thread_0);
296 	 _tx_mutex_priority_change(&thread_0, 16);
297 
298      /* Change to an even lower priority.  */
299 	 thread_0.tx_thread_user_priority =  27;
300 	 thread_0.tx_thread_user_preempt_threshold =  27;
301      _tx_mutex_priority_change(&thread_0, 28);
302 
303      /* Setup the low priority thread infromation.  */
304 	 low_priority.tx_thread_user_priority =  30;
305 	 low_priority.tx_thread_user_preempt_threshold =  29;
306      _tx_mutex_priority_change(&low_priority, 31);
307 
308      /* Change to an even lower priority.  */
309 	 thread_0.tx_thread_user_priority =  30;
310 	 thread_0.tx_thread_user_preempt_threshold =  29;
311      _tx_mutex_priority_change(&thread_0, 26);
312 
313 #ifdef TX_MANUAL_TEST
314 
315      /* Set BP here and step into code and step through the code until the internal thread resume function returns, and then issue the IRQ that modifies the core mapped.  */
316      mutex_priority_change_extension_selection =  1;
317      _tx_mutex_priority_change(&thread_0, 30);
318      thread_0.tx_thread_smp_core_mapped =  0;
319 #else
320 
321      /* Set the flag to suspend the thread and test the first condition after internal resume is called.  */
322      mutex_priority_change_extension_selection =  1;
323      threadx_mutex_suspension_priority_test =  1;
324      _tx_mutex_priority_change(&thread_0, 30);
325      thread_0.tx_thread_smp_core_mapped =  0;
326 #endif
327 
328     /* Move the thread back to priority 28.  */
329     _tx_mutex_priority_change(&thread_0, 28);
330 
331 #ifdef TX_MANUAL_TEST
332 
333      /* Set BP here and step into code and step through the code until the internal thread resume function returns, and then issue the IRQ that modifies the original priority.  */
334      mutex_priority_change_extension_selection =  2;
335      _tx_mutex_priority_change(&thread_0, 29);
336 #else
337 
338      /* Set the flag to suspend the thread and test the first condition after internal resume is called.  */
339      mutex_priority_change_extension_selection =  2;
340      threadx_mutex_suspension_priority_test =  1;
341      _tx_mutex_priority_change(&thread_0, 29);
342      _tx_thread_execute_ptr[0] =  &thread_0;
343 #endif
344 
345 #ifdef TX_MANUAL_TEST
346 
347      /* Set BP here and step into code and step through the code until the internal thread resume function returns, and then issue the IRQ that sets the original_pt_thread to NULL.  */
348      mutex_priority_change_extension_selection =  3;
349      _tx_mutex_priority_change(&thread_0, 30);
350 #else
351 
352      /* Set the flag to suspend the thread and test the first condition after internal resume is called.  */
353      mutex_priority_change_extension_selection =  3;
354      threadx_mutex_suspension_priority_test =  1;
355      _tx_mutex_priority_change(&thread_0, 30);
356 #endif
357 
358 #ifdef TX_MANUAL_TEST
359 
360      /* Set BP here and step into code and step through the code until the internal thread resume function returns, and then issue the IRQ that sets the _tx_thread_preemption__threshold_scheduled to NULL.  */
361      temp_thread =  _tx_thread_preemption__threshold_scheduled;
362      mutex_priority_change_extension_selection =  4;
363      _tx_mutex_priority_change(&thread_0, 31);
364      _tx_thread_preemption__threshold_scheduled =  temp_thread;
365 #else
366 
367      /* Set the flag to suspend the thread and test the first condition after internal resume is called.  */
368      temp_thread =  _tx_thread_preemption__threshold_scheduled;
369      mutex_priority_change_extension_selection =  4;
370      threadx_mutex_suspension_priority_test =  1;
371      _tx_mutex_priority_change(&thread_0, 31);
372      _tx_thread_preemption__threshold_scheduled =  temp_thread;
373 #endif
374 
375      /* Just change to same priority to ensure that path is executed.  */
376      mutex_priority_change_extension_selection =  0;
377      suspend_lowest_priority();
378 	 thread_0.tx_thread_user_priority =  31;
379 	 thread_0.tx_thread_user_preempt_threshold =  30;
380 	 thread_0.tx_thread_priority =  31;
381 	 thread_0.tx_thread_preempt_threshold =  30;
382      _tx_mutex_priority_change(&thread_0, 31);
383 	 thread_0.tx_thread_user_priority =  31;
384 	 thread_0.tx_thread_user_preempt_threshold =  31;
385 	 thread_0.tx_thread_priority =  31;
386 	 thread_0.tx_thread_preempt_threshold =  31;
387 	 _tx_mutex_priority_change(&thread_0, 31);
388      tx_thread_resume(&thread_0);
389 
390      /* Restore the preempt disable flag.  */
391      _tx_thread_preempt_disable--;
392 
393 	 /* Restore interrupts.  */
394 	 TX_RESTORE
395 
396      /* Successful test.  */
397      printf("SUCCESS!\n");
398      test_control_return(0);
399 }
400 
401 
thread_1_entry(ULONG thread_input)402 static void    thread_1_entry(ULONG thread_input)
403 {
404 UINT    status;
405 
406     /* Loop to get the mutex.  */
407     while(1)
408     {
409 
410         /* Get and release the mutex. */
411         status =  tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
412         if (status == TX_SUCCESS)
413           tx_mutex_put(&mutex_1);
414         tx_thread_suspend(&thread_1);
415     }
416 }
417 
418 
thread_2_entry(ULONG thread_input)419 static void    thread_2_entry(ULONG thread_input)
420 {
421 
422 UINT    status;
423 
424     /* Loop to get the mutex.  */
425     while(1)
426     {
427 
428         /* Get and release the mutex. */
429         status =  tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
430         if (status == TX_SUCCESS)
431             tx_mutex_put(&mutex_1);
432         tx_thread_suspend(&thread_2);
433     }
434 }
435 
436 
thread_3_entry(ULONG thread_input)437 static void    thread_3_entry(ULONG thread_input)
438 {
439 
440 UINT    status;
441 
442     /* Loop to get the mutex.  */
443     while(1)
444     {
445 
446         /* Get and release the mutex. */
447         status =  tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
448         if (status == TX_SUCCESS)
449             tx_mutex_put(&mutex_1);
450         tx_thread_suspend(&thread_3);
451     }
452 }
453 
thread_4_entry(ULONG thread_input)454 static void    thread_4_entry(ULONG thread_input)
455 {
456 
457 UINT    status;
458 
459     /* Loop to get the mutex.  */
460     while(1)
461     {
462 
463         /* Get and release the mutex. */
464         status =  tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
465         if (status == TX_SUCCESS)
466             tx_mutex_put(&mutex_1);
467         tx_thread_suspend(&thread_4);
468     }
469 }
470 
471 
low_priority_entry(ULONG thread_input)472 static void    low_priority_entry(ULONG thread_input)
473 {
474 }
475