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