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