1 /* This test is designed to test for simultaneous thread suspension lifting AND thread wait abort calls.  */
2 
3 #include   <stdio.h>
4 #include   "tx_api.h"
5 
6 static unsigned long   thread_0_counter =  0;
7 static TX_THREAD       thread_0;
8 
9 static unsigned long   thread_1_counter =  0;
10 static TX_THREAD       thread_1;
11 
12 static unsigned long   timer_0_counter =  0;
13 static TX_TIMER        timer_0;
14 
15 
16 static unsigned long   semaphore_put_counter =  0;
17 static unsigned long   condition_count  =  0;
18 extern UINT            _tx_timer_system_clock;
19 
20 static TX_SEMAPHORE    semaphore_0;
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    timer_0_entry(ULONG timer_input);
28 
29 /* Define the ISR dispatch.  */
30 
31 extern VOID    (*test_isr_dispatch)(void);
32 
33 
34 /* Define the external reference for the preempt disable flag.  */
35 
36 extern volatile UINT   _tx_thread_preempt_disable;
37 
38 /* Prototype for test control return.  */
39 
40 void  test_control_return(UINT status);
41 
42 
isr_entry(void)43 static void    isr_entry(void)
44 {
45 
46 UINT    status;
47 static volatile UINT miss_count = 0;
48 
49 
50     /* Attempt to sleep from a timer in order to test the error logic.  */
51     status =  tx_thread_sleep(1);
52 
53     /* Check for proper error status.  */
54     if (status != TX_CALLER_ERROR)
55     {
56 
57         /* Blow up the test to force an error.  */
58         condition_count =  10000000;
59         semaphore_put_counter =  0xFFFF0000;
60     }
61 
62     /* Determine if the interrupt occurred when the preempt disable flag was set.  */
63     if (_tx_thread_preempt_disable)
64     {
65 
66         /* Yes this is the condition we are looking for, increment the test condition counter.   */
67         condition_count++;
68     }
69 
70     /*
71     It is possible for this test to get into a resonance condition in which
72     the ISR never occurs while preemption is disabled (especially if the
73     ISR is installed in the periodic timer interrupt handler, which is
74     conveniently available). Detect this condition and break out of it by
75     perturbing the duration of this ISR a pseudo-random amount of time.
76     */
77     else if (++miss_count > 100)
78         for (miss_count = _tx_timer_system_clock % 100; miss_count != 0; --miss_count);
79 
80     /* Put the semaphore to wakeup thread 0.  */
81     status =  tx_semaphore_put(&semaphore_0);
82 
83     /* Increment the semaphore counter.  */
84     if (status == TX_SUCCESS)
85         semaphore_put_counter++;
86 }
87 
88 
89 /* Define what the initial system looks like.  */
90 
91 #ifdef CTEST
test_application_define(void * first_unused_memory)92 void test_application_define(void *first_unused_memory)
93 #else
94 void    threadx_thread_wait_abort_and_isr_application_define(void *first_unused_memory)
95 #endif
96 {
97 
98 UINT    status;
99 CHAR    *pointer;
100 
101 
102     /* Put first available memory address into a character pointer.  */
103     pointer =  (CHAR *) first_unused_memory;
104 
105     /* Put system definition stuff in here, e.g. thread creates and other assorted
106        create information.  */
107 
108     status =  tx_thread_create(&thread_0, "thread 0", thread_0_entry, 1,
109             pointer, TEST_STACK_SIZE_PRINTF,
110             17, 17, 100, TX_AUTO_START);
111     pointer = pointer + TEST_STACK_SIZE_PRINTF;
112 
113     /* Check for status.  */
114     if (status != TX_SUCCESS)
115     {
116 
117         printf("Running Thread Wait Abort and ISR Resume Test....................... ERROR #1\n");
118         test_control_return(1);
119     }
120 
121     status =  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
122             pointer, TEST_STACK_SIZE_PRINTF,
123             17, 17, 100, TX_AUTO_START);
124     pointer = pointer + TEST_STACK_SIZE_PRINTF;
125 
126     /* Check for status.  */
127     if (status != TX_SUCCESS)
128     {
129 
130         printf("Running Thread Wait Abort and ISR Resume Test....................... ERROR #2\n");
131         test_control_return(1);
132     }
133 
134     /* Create semaphore - consumer producer semaphore.  */
135     status =  tx_semaphore_create(&semaphore_0, "semaphore 0", 0);
136 
137     /* Check for status.  */
138     if (status != TX_SUCCESS)
139     {
140 
141         printf("Running Thread Wait Abort and ISR Resume Test....................... ERROR #3\n");
142         test_control_return(1);
143     }
144 
145     /* Create a timer to ensure a context save is called for every interrupt.  */
146     status =  tx_timer_create(&timer_0, "timer 0", timer_0_entry, 0, 1, 1, TX_AUTO_ACTIVATE);
147 
148     /* Check for status.  */
149     if (status != TX_SUCCESS)
150     {
151 
152         printf("Running Thread Wait Abort and ISR Resume Test....................... ERROR #4\n");
153         test_control_return(1);
154     }
155 
156     /* Clear the condition count variable.  */
157     condition_count  =  0;
158 }
159 
160 
161 
162 /* Define the test threads.  */
163 
thread_0_entry(ULONG thread_input)164 static void    thread_0_entry(ULONG thread_input)
165 {
166 
167 UINT    status;
168 
169 
170     /* Setup ISR for this test.  */
171     test_isr_dispatch =  isr_entry;
172 
173     /* Inform user.  */
174     printf("Running Thread Wait Abort and ISR Resume Test....................... ");
175 
176     /* Loop to exploit the probability window inside tx_thread_wait_abort.  */
177     while (condition_count < 10)
178     {
179 
180         /* Suspend on the semaphore that is going to be set via the ISR.  */
181         status =  tx_semaphore_get(&semaphore_0, (thread_0_counter % 5) + 1);
182 
183         /* Determine if we have an unexpected result.  */
184         if ((status != TX_SUCCESS) && (status != TX_WAIT_ABORTED))
185         {
186 
187             /* Test error!  */
188             printf("ERROR #5\n");
189             test_control_return(1);
190         }
191 
192         /* Check for the preempt disable flag being set.  */
193         if (_tx_thread_preempt_disable)
194         {
195 
196             /* Test error!  */
197             printf("ERROR #6\n");
198             test_control_return(2);
199         }
200 
201         /* Determine if we really got the semaphore.  */
202         if (status == TX_SUCCESS)
203         {
204 
205             /* Increment the thread count.  */
206             thread_0_counter++;
207 
208 #ifdef TX_NOT_INTERRUPTABLE
209 
210             /* Determine if we have a non-interruptable build of ThreadX. If so, just
211                get out of this loop after 100 passes.  */
212 
213             if (thread_0_counter >= 100)
214                 break;
215 #endif
216 
217         }
218     }
219 
220     /* Clear ISR dispatch.  */
221     test_isr_dispatch =  TX_NULL;
222 
223 #ifdef TX_NOT_INTERRUPTABLE
224     /* At this point, check to see if we got all the semaphores!  */
225     if ((thread_0_counter != (semaphore_put_counter - semaphore_0.tx_semaphore_count)) ||
226         (condition_count != 0))
227 #else
228     /* At this point, check to see if we got all the semaphores!  */
229     if (thread_0_counter != (semaphore_put_counter - semaphore_0.tx_semaphore_count))
230 #endif
231     {
232 
233         /* Test error!  */
234         printf("ERROR #7\n");
235         test_control_return(3);
236     }
237     else
238     {
239 
240         /* Successful test.  */
241         printf("SUCCESS!\n");
242         test_control_return(0);
243     }
244 }
245 
246 
thread_1_entry(ULONG thread_input)247 static void    thread_1_entry(ULONG thread_input)
248 {
249 
250     /* Loop forever!  */
251     while(1)
252     {
253 
254 
255         /* Abort the suspension on the semaphore in thread 0.  */
256         tx_thread_wait_abort(&thread_0);
257 
258         /* Increment the thread counter.  */
259         thread_1_counter++;
260 
261         /* Let thread 0 run again!  */
262         tx_thread_relinquish();
263     }
264 }
265 
266 
timer_0_entry(ULONG input)267 static void    timer_0_entry(ULONG input)
268 {
269     timer_0_counter++;
270 }
271 
272