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