1 /* This test is designed to test the mutex suspension and priority inheritance with another
2    thread resuming the higher priority thread by doing a mutex put.  Higher-priority thread should preempt.  */
3 
4 #include   <stdio.h>
5 #include   "tx_api.h"
6 
7 static unsigned long   thread_0_counter =  0;
8 static TX_THREAD       thread_0;
9 
10 static unsigned long   thread_1_counter =  0;
11 static TX_THREAD       thread_1;
12 
13 static unsigned long   thread_2_counter =  0;
14 static TX_THREAD       thread_2;
15 static TX_THREAD       thread_3;
16 
17 static unsigned long   thread_4_counter =  0;
18 static TX_THREAD       thread_4;
19 
20 static unsigned long   thread_5_counter =  0;
21 static TX_THREAD       thread_5;
22 
23 static unsigned long   thread_6_counter =  0;
24 static TX_THREAD       thread_6;
25 
26 static unsigned long   thread_7_counter =  0;
27 static TX_THREAD       thread_7;
28 
29 static TX_MUTEX        mutex_0;
30 static TX_MUTEX        mutex_1;
31 static TX_MUTEX        mutex_2;
32 static TX_MUTEX        mutex_3;
33 
34 
35 extern UINT            test_mutex_from_init;
36 extern TEST_FLAG       test_forced_mutex_timeout;
37 
38 
39 VOID        _tx_mutex_priority_change(TX_THREAD *thread_ptr, UINT priority, UINT threshold);
40 
41 
42 
43 /* Define thread prototypes.  */
44 
45 static void    thread_0_entry(ULONG thread_input);
46 static void    thread_1_entry(ULONG thread_input);
47 static void    thread_2_entry(ULONG thread_input);
48 static void    thread_4_entry(ULONG thread_input);
49 static void    thread_5_entry(ULONG thread_input);
50 static void    thread_6_entry(ULONG thread_input);
51 static void    thread_7_entry(ULONG thread_input);
52 
53 
54 /* Prototype for test control return.  */
55 void  test_control_return(UINT status);
56 
57 
58 /* Define what the initial system looks like.  */
59 
60 #ifdef CTEST
test_application_define(void * first_unused_memory)61 void test_application_define(void *first_unused_memory)
62 #else
63 void    threadx_mutex_priority_inheritance_application_define(void *first_unused_memory)
64 #endif
65 {
66 
67 UINT    status;
68 CHAR    *pointer;
69 
70 
71     /* Put first available memory address into a character pointer.  */
72     pointer =  (CHAR *) first_unused_memory;
73 
74     /* Test for an error creating/using a mutex from initialization.  */
75     if (test_mutex_from_init != TX_SUCCESS)
76     {
77 
78         printf("Running Mutex Priority Inheritance Test............................. ERROR #0\n");
79         test_control_return(1);
80     }
81 
82     /* Put system definition stuff in here, e.g. thread creates and other assorted
83        create information.  */
84 
85     status =  tx_thread_create(&thread_0, "thread 0", thread_0_entry, 1,
86             pointer, TEST_STACK_SIZE_PRINTF,
87             16, 16, 100, TX_AUTO_START);
88     pointer = pointer + TEST_STACK_SIZE_PRINTF;
89 
90     /* Check for status.  */
91     if (status != TX_SUCCESS)
92     {
93 
94         printf("Running Mutex Priority Inheritance Test............................. ERROR #1\n");
95         test_control_return(1);
96     }
97 
98     status =  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
99             pointer, TEST_STACK_SIZE_PRINTF,
100             15, 15, 100, TX_DONT_START);
101     pointer = pointer + TEST_STACK_SIZE_PRINTF;
102 
103     /* Check for status.  */
104     if (status != TX_SUCCESS)
105     {
106 
107         printf("Running Mutex Priority Inheritance Test............................. ERROR #2\n");
108         test_control_return(1);
109     }
110 
111     status =  tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
112             pointer, TEST_STACK_SIZE_PRINTF,
113             14, 14, 100, TX_DONT_START);
114     pointer = pointer + TEST_STACK_SIZE_PRINTF;
115 
116     /* Check for status.  */
117     if (status != TX_SUCCESS)
118     {
119 
120         printf("Running Mutex Priority Inheritance Test............................. ERROR #3\n");
121         test_control_return(1);
122     }
123 
124     /* Create a high-priority thread that will get all the priority inheritance mutexes and return from
125        it's entry function in order to test the auto delete feature.  */
126     status =  tx_thread_create(&thread_4, "thread 4", thread_4_entry, 4,
127             pointer, TEST_STACK_SIZE_PRINTF,
128             10, 10, 100, TX_DONT_START);
129     pointer = pointer + TEST_STACK_SIZE_PRINTF;
130 
131     /* Check for status.  */
132     if (status != TX_SUCCESS)
133     {
134 
135         printf("Running Mutex Priority Inheritance Test............................. ERROR #4\n");
136         test_control_return(1);
137     }
138 
139     /* Create a higher-priority thread that is used to get thread 4 into a priority inheritance state.  */
140     status =  tx_thread_create(&thread_5, "thread 5", thread_5_entry, 5,
141             pointer, TEST_STACK_SIZE_PRINTF,
142             8, 8, 100, TX_DONT_START);
143     pointer = pointer + TEST_STACK_SIZE_PRINTF;
144 
145     /* Check for status.  */
146     if (status != TX_SUCCESS)
147     {
148 
149         printf("Running Mutex Priority Inheritance Test............................. ERROR #5\n");
150         test_control_return(1);
151     }
152 
153 
154     /* Create a higher-priority thread that is used to suspend on priority inheritance mutex 3.  */
155     status =  tx_thread_create(&thread_6, "thread 6", thread_6_entry, 6,
156             pointer, TEST_STACK_SIZE_PRINTF,
157             6, 6, 100, TX_DONT_START);
158     pointer = pointer + TEST_STACK_SIZE_PRINTF;
159 
160     /* Check for status.  */
161     if (status != TX_SUCCESS)
162     {
163 
164         printf("Running Mutex Priority Inheritance Test............................. ERROR #6\n");
165         test_control_return(1);
166     }
167 
168 
169     /* Create a higher-priority thread that is used to suspend on priority inheritance mutex 3.  */
170     status =  tx_thread_create(&thread_7, "thread 7", thread_7_entry, 7,
171             pointer, TEST_STACK_SIZE_PRINTF,
172             7, 7, 100, TX_DONT_START);
173     pointer = pointer + TEST_STACK_SIZE_PRINTF;
174 
175     /* Check for status.  */
176     if (status != TX_SUCCESS)
177     {
178 
179         printf("Running Mutex Priority Inheritance Test............................. ERROR #7\n");
180         test_control_return(1);
181     }
182 
183     /* Create a mutex.  */
184     status =  tx_mutex_create(&mutex_0, "mutex 0", TX_INHERIT);
185 
186     /* Check for status.  */
187     if (status != TX_SUCCESS)
188     {
189 
190         printf("Running Mutex Priority Inheritance Test............................. ERROR #8\n");
191         test_control_return(1);
192     }
193 
194     /* Create another mutex.  */
195     status =  tx_mutex_create(&mutex_1, "mutex 1", TX_INHERIT);
196 
197     /* Check for status.  */
198     if (status != TX_SUCCESS)
199     {
200 
201         printf("Running Mutex Priority Inheritance Test............................. ERROR #9\n");
202         test_control_return(1);
203     }
204 
205     /* Create another mutex.  */
206     status =  tx_mutex_create(&mutex_2, "mutex 2", TX_INHERIT);
207 
208     /* Check for status.  */
209     if (status != TX_SUCCESS)
210     {
211 
212         printf("Running Mutex Priority Inheritance Test............................. ERROR #10\n");
213         test_control_return(1);
214     }
215 
216     /* Create another mutex.  */
217     status =  tx_mutex_create(&mutex_3, "mutex 3", TX_INHERIT);
218 
219     /* Check for status.  */
220     if (status != TX_SUCCESS)
221     {
222 
223         printf("Running Mutex Priority Inheritance Test............................. ERROR #11\n");
224         test_control_return(1);
225     }
226 
227     /* Drive one path of the internal mutex priority change routine directly for code coverage.  */
228     thread_3.tx_thread_user_priority =   1;
229     thread_3.tx_thread_user_preempt_threshold =  1;
230     thread_3.tx_thread_state =  4;
231     _tx_mutex_priority_change(&thread_3, 3, 3);
232 }
233 
234 
235 
236 /* Define the test threads.  */
237 
thread_0_entry(ULONG thread_input)238 static void    thread_0_entry(ULONG thread_input)
239 {
240 
241 UINT    status;
242 
243 
244     /* Inform user.  */
245     printf("Running Mutex Priority Inheritance Test............................. ");
246 
247     /* Resume thread 4 to test the automatic release of the mutexes.  */
248     tx_thread_resume(&thread_4);
249 
250     /* Determine if thread 4 was able to get the mutexes before completion... and
251        have its original priority restored after the priority inheritance.  */
252     if ((thread_4_counter != 1) || (thread_5_counter != 1) || (thread_4.tx_thread_priority != 10) ||
253         (thread_4.tx_thread_inherit_priority != TX_MAX_PRIORITIES))
254     {
255 
256         /* Mutex error.  */
257         printf("ERROR #12\n");
258         test_control_return(1);
259     }
260 
261     /* Increment thread 0 counter.  */
262     thread_0_counter++;
263 
264     /* Get all the mutexex.  */
265     status =  tx_mutex_get(&mutex_0, TX_NO_WAIT);
266     status += tx_mutex_get(&mutex_1, TX_NO_WAIT);
267     status += tx_mutex_get(&mutex_2, TX_NO_WAIT);
268 
269     /* Should be successful.  */
270     if (status != TX_SUCCESS)
271     {
272 
273         /* Mutex error.  */
274         printf("ERROR #13\n");
275         test_control_return(1);
276     }
277 
278     /* Release mutex 2 to be compatible with original test.  */
279     tx_mutex_put(&mutex_2);
280 
281     /* Now resume the higher priority thread to cause suspension.  */
282     tx_thread_resume(&thread_1);
283 
284     /* The other thread should now be suspended on the mutex.  */
285     if ((thread_1_counter != 1) || (thread_0.tx_thread_priority != 15))
286     {
287 
288         /* Mutex error.  */
289         printf("ERROR #14\n");
290         test_control_return(1);
291     }
292 
293     /* Release the mutex, this should cause the other thread
294        to preempt.  */
295     status =  tx_mutex_put(&mutex_0);
296 
297     /* Check status and run counter of other thread.  */
298     if ((status != TX_SUCCESS) || (thread_1_counter != 2) || (thread_0.tx_thread_priority != 16))
299     {
300 
301         /* Mutex error.  */
302         printf("ERROR #15\n");
303         test_control_return(1);
304     }
305 
306     /* At this point, get the mutex again.  */
307     status =  tx_mutex_get(&mutex_0, TX_NO_WAIT);
308 
309     /* Should be successful.  */
310     if (status != TX_SUCCESS)
311     {
312 
313         /* Mutex error.  */
314         printf("ERROR #16\n");
315         test_control_return(1);
316     }
317 
318     /* Now sleep for 20 ticks in order to test the priority inheritance change of a
319        non-ready thread.  */
320     tx_thread_sleep(20);
321 
322     /* The other thread should now be suspended on the mutex.  */
323     if ((thread_1_counter != 3) || (thread_0.tx_thread_priority != 15))
324     {
325 
326         /* Mutex error.  */
327         printf("ERROR #17\n");
328         test_control_return(1);
329     }
330 
331     /* Resume thread 2 in order to get two threads suspended on the mutex.  */
332     tx_thread_resume(&thread_2);
333 
334     /* Now do a mutex put to release both threads suspended on this mutex.  */
335     status =  tx_mutex_put(&mutex_0);
336 
337     /* The other thread should now be suspended on the mutex.  */
338     if ((status != TX_SUCCESS) || (thread_1_counter != 4) || (thread_2_counter != 2) || (thread_0.tx_thread_priority != 16))
339     {
340 
341         /* Mutex error.  */
342         printf("ERROR #18\n");
343         test_control_return(1);
344     }
345 
346     /* At this point, get the mutex again.  */
347     status =  tx_mutex_get(&mutex_0, TX_NO_WAIT);
348 
349     /* Should be successful.  */
350     if (status != TX_SUCCESS)
351     {
352 
353         /* Mutex error.  */
354         printf("ERROR #19\n");
355         test_control_return(1);
356     }
357 
358     /* Abort the sleep.  */
359     tx_thread_wait_abort(&thread_1);
360     tx_thread_wait_abort(&thread_2);
361 
362     /* Now both threads are suspended again on mutex... and then terminate them.  */
363     tx_thread_terminate(&thread_1);
364     tx_thread_terminate(&thread_2);
365 
366     /* Now do a mutex put to release both threads suspended on this mutex.  */
367     status =  tx_mutex_put(&mutex_0);
368 
369     /* The other thread should now be suspended on the mutex.  */
370     if ((status != TX_SUCCESS) || (thread_1_counter != 5) || (thread_2_counter != 3) || (thread_0.tx_thread_priority != 16))
371     {
372 
373         /* Mutex error.  */
374         printf("ERROR #20\n");
375         test_control_return(1);
376     }
377 
378     /* Now test the timeout on the suspension list of a priority inheritance mutex.  */
379 
380     /* First, obtain priority inheritance mutex 3.  */
381     status =  tx_mutex_get(&mutex_3, TX_WAIT_FOREVER);
382 
383     /* Next resume threads 6 and 7 so they will block on trying to get this mutex forever.  */
384     status += tx_thread_resume(&thread_7);
385     status += tx_thread_resume(&thread_6);
386 
387     /* Now set the flag which will cause the last thread in the suspension list to timeout (abort)
388        resulting in a NULL suspension list and covering that branch condition in tx_mutex_put  */
389     test_forced_mutex_timeout =  1;
390 
391     /* Perform a mutex put to release the mutex.  */
392     status += tx_mutex_put(&mutex_3);
393 
394     /* Now check for errors.  */
395 #ifndef TX_MISRA_ENABLE
396 #ifndef TX_MANUAL_TEST
397 #ifndef TX_NOT_INTERRUPTABLE
398     if ((status != TX_SUCCESS) || (thread_6_counter != 1) || (thread_7_counter != 0))
399 #else
400     if ((status != TX_SUCCESS) || (thread_6_counter != 1))
401 #endif
402 #else
403     if ((status != TX_SUCCESS) || (thread_6_counter != 1))
404 #endif
405 #else
406     if ((status != TX_SUCCESS) || (thread_6_counter != 1))
407 #endif
408     {
409 
410         /* Mutex error.  */
411         printf("ERROR #21\n");
412         test_control_return(1);
413     }
414     else
415     {
416 
417         /* Successful test.  */
418         printf("SUCCESS!\n");
419         test_control_return(0);
420     }
421 }
422 
423 
thread_1_entry(ULONG thread_input)424 static void    thread_1_entry(ULONG thread_input)
425 {
426 
427 UINT    status;
428 
429 
430     while(1)
431     {
432 
433         /* Increment thread run counter.  */
434         thread_1_counter++;
435 
436         /* Suspend on the mutex. */
437         status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
438         status += tx_mutex_put(&mutex_0);
439 
440         /* Did we get the right status?  */
441         if (status == TX_SUCCESS)
442             thread_1_counter++;
443 
444         /* Sleep for 10 ticks... to delay.  */
445         tx_thread_sleep(10);
446     }
447 }
448 
449 
thread_2_entry(ULONG thread_input)450 static void    thread_2_entry(ULONG thread_input)
451 {
452 
453 UINT    status;
454 
455 
456     /* Get mutex to cause additional ownership linked-list processing.  */
457     tx_mutex_get(&mutex_2, TX_WAIT_FOREVER);
458 
459     while(1)
460     {
461 
462         /* Increment thread run counter.  */
463         thread_2_counter++;
464 
465         /* Suspend on the mutex. */
466         status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
467         status += tx_mutex_put(&mutex_0);
468 
469         /* Did we get the right status?  */
470         if (status == TX_SUCCESS)
471             thread_2_counter++;
472 
473         /* Sleep for 10 ticks... to delay.  */
474         tx_thread_sleep(10);
475     }
476 }
477 
478 
thread_4_entry(ULONG thread_input)479 static void    thread_4_entry(ULONG thread_input)
480 {
481 
482 UINT    status;
483 UINT    old_priority;
484 
485 
486     /* Get mutex to cause additional ownership linked-list processing.  */
487     status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
488     status += tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
489     status += tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
490     status += tx_mutex_get(&mutex_1, TX_WAIT_FOREVER);
491     status += tx_mutex_get(&mutex_2, TX_WAIT_FOREVER);
492 
493     /* Resume thread 5 to get into priority inheritance.  */
494     tx_thread_resume(&thread_5);
495 
496     /* Determine if all the mutex gets were successful... and we have
497        inherited priority 8.  */
498     if ((status == TX_SUCCESS) && (thread_4.tx_thread_priority == 8))
499     {
500 
501         /* Yes, increment the thread counter.  */
502         thread_4_counter++;
503     }
504 
505     /* Now, attempt to manually set this thread's priority to the same priority.  */
506     status =  tx_thread_priority_change(&thread_4, 8, &old_priority);
507 
508     /* Determine if there is an error.  */
509     if ((status != TX_SUCCESS) || (thread_4.tx_thread_user_priority != 8) || (old_priority != 10))
510     {
511 
512         /* Clear the counter, which will signal an error to the thread above.  */
513         thread_4_counter =  0;
514     }
515 
516     /* Now attempt to manually set the same thread priority.  */
517     status =  tx_thread_priority_change(&thread_4, 8, &old_priority);
518 
519     /* Determine if there is an error.  */
520     if ((status != TX_SUCCESS) || (thread_4.tx_thread_user_priority != 8) || (old_priority != 8))
521     {
522 
523         /* Clear the counter, which will signal an error to the thread above.  */
524         thread_4_counter =  0;
525     }
526 
527     /* Now restore the original user priority of 10.  */
528     status =  tx_thread_priority_change(&thread_4, 10, &old_priority);
529 
530     /* Determine if there is an error.  */
531     if ((status != TX_SUCCESS) || (thread_4.tx_thread_user_priority != 10) || (old_priority != 8))
532     {
533 
534         /* Clear the counter, which will signal an error to the thread above.  */
535         thread_4_counter =  0;
536     }
537 
538     /* Now fall through and make sure the mutex cleanup function
539        releases all the mutexes.  */
540 }
541 
542 
thread_5_entry(ULONG thread_input)543 static void    thread_5_entry(ULONG thread_input)
544 {
545 
546 UINT    status;
547 
548 
549     /* Get mutex to cause priority inheritance in thread 4.  */
550     status =  tx_mutex_get(&mutex_0, TX_WAIT_FOREVER);
551 
552     /* Determine if all the mutex gets were successful.  */
553     if (status == TX_SUCCESS)
554     {
555 
556         /* Yes, increment the thread counter.  */
557         thread_5_counter++;
558     }
559 
560     /* Now fall through and make sure the mutex cleanup function
561        releases all the mutexes.  */
562 }
563 
564 
thread_6_entry(ULONG thread_input)565 static void    thread_6_entry(ULONG thread_input)
566 {
567 
568 UINT    status;
569 
570 
571     /* Get mutex to cause priority inheritance in thread 0.  */
572     status =  tx_mutex_get(&mutex_3, TX_WAIT_FOREVER);
573 
574     /* Determine if all the mutex gets were successful.  */
575     if (status == TX_SUCCESS)
576     {
577 
578         /* Yes, increment the thread counter.  */
579         thread_6_counter++;
580     }
581 
582     /* Now fall through and make sure the mutex cleanup function
583        releases all the mutexes.  */
584 }
585 
586 
thread_7_entry(ULONG thread_input)587 static void    thread_7_entry(ULONG thread_input)
588 {
589 
590 UINT    status;
591 
592 
593     /* Get mutex to cause priority inheritance in thread 0.  */
594     status =  tx_mutex_get(&mutex_3, TX_WAIT_FOREVER);
595 
596     /* Determine if all the mutex gets were successful.  */
597     if (status == TX_SUCCESS)
598     {
599 
600         /* Yes, increment the thread counter.  */
601         thread_7_counter++;
602     }
603 
604     /* Now fall through and make sure the mutex cleanup function
605        releases all the mutexes.  */
606 }
607 
608