1 /* This test is designed to test for simultaneous thread event flag set AND ISR event flag set and clear.  */
2 
3 #include   <stdio.h>
4 #include   "tx_api.h"
5 
6 
7 /* Define the ISR dispatch.  */
8 
9 extern VOID    (*test_isr_dispatch)(void);
10 
11 
12 /* Prototype for test control return.  */
13 void  test_control_return(UINT status);
14 
15 
16 static unsigned long   thread_0_counter =  0;
17 static TX_THREAD       thread_0;
18 
19 static unsigned long   thread_1_counter =  0;
20 static TX_THREAD       thread_1;
21 
22 static unsigned long   thread_2_counter =  0;
23 static TX_THREAD       thread_2;
24 
25 static unsigned long   timer_0_counter =  0;
26 static TX_TIMER        timer_0;
27 
28 static unsigned long   event_flags_set_counter =  0;
29 static unsigned long   condition_count =  0;
30 
31 static TX_EVENT_FLAGS_GROUP    event_flags_0;
32 
33 extern UINT _tx_thread_preempt_disable;
34 extern UINT _tx_timer_system_clock;
35 
36 
37 /* Define thread prototypes.  */
38 
39 static void    thread_0_entry(ULONG thread_input);
40 static void    thread_1_entry(ULONG thread_input);
41 static void    thread_2_entry(ULONG thread_input);
42 static void    timer_0_entry(ULONG timer_input);
43 
44 
event_set_notify(TX_EVENT_FLAGS_GROUP * group)45 static void event_set_notify(TX_EVENT_FLAGS_GROUP *group)
46 {
47 
48     /* Not necessary to do anything in this function.  */
49 }
50 
51 
test_isr(void)52 static void    test_isr(void)
53 {
54 
55 UINT    status;
56 ULONG   actual;
57 static volatile UINT miss_count = 0;
58 
59 
60     /* Determine if the interrupt occurred when the preempt disable flag was set.  */
61     if (_tx_thread_preempt_disable)
62     {
63 
64         /* Yes this is the condition we are looking for, increment the test condition counter.   */
65         condition_count++;
66     }
67 
68     /*
69     It is possible for this test to get into a resonance condition in which
70     the ISR never occurs while preemption is disabled (especially if the
71     ISR is installed in the periodic timer interrupt handler, which is
72     conveniently available). Detect this condition and break out of it by
73     perturbing the duration of this ISR a pseudo-random amount of time.
74     */
75     else if (++miss_count > 100)
76     {
77         for (miss_count = _tx_timer_system_clock % 100; miss_count != 0; --miss_count);
78     }
79 
80     if (((event_flags_0.tx_event_flags_group_current & 0x3) == 0) &&
81         (event_flags_0.tx_event_flags_group_suspended_count == 2))
82     {
83 
84         /* Put the event_flags to wakeup thread 0.  */
85         status =  tx_event_flags_set(&event_flags_0, 0x3, TX_OR);
86 
87         /* Clear the same flags immediately.  */
88         status += tx_event_flags_set(&event_flags_0, 0xFFFFFFFC, TX_AND);
89 
90         /* Setup some event flags just so we can clear them.  */
91         status +=  tx_event_flags_set(&event_flags_0, 0x30000, TX_OR);
92 
93         /* Clear the same flags immediately.  */
94         status += tx_event_flags_set(&event_flags_0, 0xFFFEFFFF, TX_AND);
95 
96         /* Clear the same flags immediately.  */
97         status += tx_event_flags_set(&event_flags_0, 0xFFFDFFFC, TX_AND);
98 
99         /* Check for an error.  */
100         if (status)
101             return;
102 
103         /* Get the events from an ISR.  */
104         status =  tx_event_flags_get(&event_flags_0, 0x30000, TX_OR, &actual, TX_NO_WAIT);
105 
106         /* Check to make sure this results in an error.  */
107         if (status != TX_NO_EVENTS)
108             return;
109 
110         /* Do a set and a get consume from an ISR.  */
111         status =  tx_event_flags_set(&event_flags_0, 0x000000C0, TX_OR);
112 
113         status += tx_event_flags_get(&event_flags_0, 0x00000080, TX_OR, &actual, TX_NO_WAIT);
114 
115         status += tx_event_flags_get(&event_flags_0, 0x000000C0, TX_OR_CLEAR, &actual, TX_NO_WAIT);
116 
117         /* Increment the event_flags counter.  */
118         if ((status == TX_SUCCESS) && (actual == 0xC4))
119         {
120             event_flags_set_counter++;
121         }
122     }
123 }
124 
125 
126 /* Define what the initial system looks like.  */
127 
128 #ifdef CTEST
test_application_define(void * first_unused_memory)129 void test_application_define(void *first_unused_memory)
130 #else
131 void    threadx_event_flag_isr_set_clear_application_define(void *first_unused_memory)
132 #endif
133 {
134 
135 UINT    status;
136 CHAR    *pointer;
137 
138 
139     /* Put first available memory address into a character pointer.  */
140     pointer =  (CHAR *) first_unused_memory;
141 
142     /* Put system definition stuff in here, e.g. thread creates and other assorted
143        create information.  */
144 
145     status =  tx_thread_create(&thread_2, "thread 2", thread_2_entry, 2,
146             pointer, TEST_STACK_SIZE_PRINTF,
147             17, 17, 100, TX_AUTO_START);
148     pointer = pointer + TEST_STACK_SIZE_PRINTF;
149 
150     /* Check for status.  */
151     if (status != TX_SUCCESS)
152     {
153 
154         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #1\n");
155         test_control_return(1);
156     }
157 
158     status =  tx_thread_create(&thread_0, "thread 0", thread_0_entry, 1,
159             pointer, TEST_STACK_SIZE_PRINTF,
160             17, 17, 100, TX_AUTO_START);
161     pointer = pointer + TEST_STACK_SIZE_PRINTF;
162 
163     /* Check for status.  */
164     if (status != TX_SUCCESS)
165     {
166 
167         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #2\n");
168         test_control_return(1);
169     }
170 
171     status =  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 1,
172             pointer, TEST_STACK_SIZE_PRINTF,
173             17, 17, 100, TX_AUTO_START);
174     pointer = pointer + TEST_STACK_SIZE_PRINTF;
175 
176     /* Check for status.  */
177     if (status != TX_SUCCESS)
178     {
179 
180         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #3\n");
181         test_control_return(1);
182     }
183 
184     /* Create event flags group.  */
185     status =  tx_event_flags_create(&event_flags_0, "event_flags 0");
186 
187     /* Check for status.  */
188     if (status != TX_SUCCESS)
189     {
190 
191         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #4\n");
192         test_control_return(1);
193     }
194 
195     /* Create a timer to ensure a context save is called for every interrupt.  */
196     status =  tx_timer_create(&timer_0, "timer 0", timer_0_entry, 0, 1, 1, TX_AUTO_ACTIVATE);
197 
198     /* Check for status.  */
199     if (status != TX_SUCCESS)
200     {
201 
202         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #5\n");
203         test_control_return(1);
204     }
205 
206     /* Register the event set notify function.  */
207     status =  tx_event_flags_set_notify(&event_flags_0, event_set_notify);
208 
209 #ifndef TX_DISABLE_NOTIFY_CALLBACKS
210 
211     /* Check status.  */
212     if (status != TX_SUCCESS)
213     {
214 
215         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #6\n");
216         test_control_return(1);
217     }
218 #else
219 
220     /* Check status.  */
221     if (status != TX_FEATURE_NOT_ENABLED)
222     {
223 
224         printf("Running Event Flag Set/Clear from ISR Test.......................... ERROR #7\n");
225         test_control_return(1);
226     }
227 
228 #endif
229 }
230 
231 
232 
233 /* Define the test threads.  */
234 
thread_0_entry(ULONG thread_input)235 static void    thread_0_entry(ULONG thread_input)
236 {
237 
238 UINT    status;
239 ULONG   actual;
240 
241 
242     /* Inform user.  */
243     printf("Running Event Flag Set/Clear from ISR Test.......................... ");
244 
245     /* Setup the test ISR.  */
246     test_isr_dispatch =  test_isr;
247 
248     /* Loop to exploit the probability window inside tx_event_flags_set call.  */
249     while (condition_count < 40)
250     {
251 
252         /* Suspend on the event_flags that is going to be set via the ISR.  */
253         status =  tx_event_flags_get(&event_flags_0, 2, TX_OR_CLEAR, &actual, 4);
254 
255         /* Determine if we have an unexpected result.  */
256         if (status != TX_SUCCESS)
257         {
258 
259             /* Test error!  */
260             printf("ERROR #8\n");
261             test_control_return(1);
262         }
263 
264         /* Check for the preempt disable flag being set.  */
265         if (_tx_thread_preempt_disable)
266         {
267 
268             /* Test error!  */
269             printf("ERROR #9\n");
270             test_control_return(2);
271         }
272 
273         /* Determine if we really got the event_flags.  */
274         if (status == TX_SUCCESS)
275         {
276 
277             /* Increment the thread count.  */
278             thread_0_counter++;
279         }
280     }
281 
282     /* Setup the test ISR.  */
283     test_isr_dispatch =  TX_NULL;
284 
285     /* Let the other threads run once more...  */
286     tx_thread_relinquish();
287 
288     /* At this point, check to see if we got all the event_flagss!  */
289     if ((thread_0_counter != event_flags_set_counter) ||
290         (thread_1_counter != event_flags_set_counter))
291     {
292 
293         /* Test error!  */
294         printf("ERROR #10\n");
295         test_control_return(3);
296     }
297     else
298     {
299 
300         /* Successful test.  */
301         printf("SUCCESS!\n");
302         test_control_return(0);
303     }
304 }
305 
306 
thread_1_entry(ULONG thread_input)307 static void    thread_1_entry(ULONG thread_input)
308 {
309 
310 UINT    status;
311 ULONG   actual;
312 
313 
314     /* Loop to exploit the probability window inside tx_event_flags_set call.  */
315     while (1)
316     {
317 
318         /* Suspend on the event_flags that is going to be set via the ISR.  */
319         status =  tx_event_flags_get(&event_flags_0, 1, TX_OR_CLEAR, &actual, 4);
320 
321         /* Determine if we have an unexpected result.  */
322         if (status != TX_SUCCESS)
323         {
324 
325             break;
326         }
327 
328         /* Increment this thread's counter.  */
329         thread_1_counter++;
330     }
331 }
332 
333 
thread_2_entry(ULONG thread_input)334 static void    thread_2_entry(ULONG thread_input)
335 {
336 
337     /* Loop forever!  */
338     while(1)
339     {
340 
341 
342         /* Set event flags - not the one needed by threads 0 and 1.  */
343         tx_event_flags_set(&event_flags_0, 0x4, TX_OR);
344 
345         /* Increment the thread counter.  */
346         thread_2_counter++;
347 
348         /* Let thread 0 run again!  */
349         tx_thread_relinquish();
350     }
351 }
352 
353 
timer_0_entry(ULONG input)354 static void    timer_0_entry(ULONG input)
355 {
356     timer_0_counter++;
357 }
358 
359 
360