1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Source: criticalsectionfunctions/test4/test4.c
8**
9** Purpose: Test to see if threads blocked on a CRITICAL_SECTION object will
10** be released in an orderly manner. This case looks at the following
11** scenario. If one thread owns a CRITICAL_SECTION object and two threads
12** block in EnterCriticalSection, trying to hold the already owned
13** CRITICAL_SECTION object, when the first thread releases the CRITICAL_SECTION
14** object, will one and only one of the waiters get unblocked?
15**
16** Dependencies: CreateThread
17** InitializeCriticalSection
18** EnterCriticalSection
19** LeaveCriticalSection
20** DeleteCriticalSection
21** Sleep
22** WaitForSingleObject
23**
24
25**
26**=========================================================*/
27
28#include <palsuite.h>
29
30#define NUM_BLOCKING_THREADS 2
31
32BOOL bTestResult;
33CRITICAL_SECTION CriticalSection;
34HANDLE hThread[NUM_BLOCKING_THREADS];
35HANDLE hEvent;
36DWORD dwThreadId[NUM_BLOCKING_THREADS];
37volatile int flags[NUM_BLOCKING_THREADS] = {0,0};
38
39DWORD PALAPI ThreadTest1(LPVOID lpParam)
40{
41
42 EnterCriticalSection ( &CriticalSection );
43
44 flags[0] = 1;
45
46 return 0;
47
48}
49
50DWORD PALAPI ThreadTest2(LPVOID lpParam)
51{
52
53 EnterCriticalSection ( &CriticalSection );
54
55 flags[1] = 1;
56
57 return 0;
58
59}
60
61int __cdecl main(int argc, char **argv)
62{
63
64 DWORD dwRet;
65 DWORD dwRet1;
66 bTestResult = FAIL;
67
68 if ((PAL_Initialize(argc,argv)) != 0)
69 {
70 return(bTestResult);
71 }
72
73 /*
74 * Create Critical Section Object
75 */
76 InitializeCriticalSection ( &CriticalSection );
77
78 EnterCriticalSection ( &CriticalSection );
79
80 hThread[0] = CreateThread(NULL,
81 0,
82 &ThreadTest1,
83 (LPVOID) 0,
84 CREATE_SUSPENDED,
85 &dwThreadId[0]);
86 if (hThread[0] == NULL)
87 {
88 Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
89 "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest1,
90 (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[0], GetLastError());
91 LeaveCriticalSection(&CriticalSection);
92 DeleteCriticalSection ( &CriticalSection );
93 Fail("");
94 }
95
96 hThread[1] = CreateThread(NULL,
97 0,
98 &ThreadTest2,
99 (LPVOID) 0,
100 CREATE_SUSPENDED,
101 &dwThreadId[1]);
102 if (hThread[1] == NULL)
103 {
104 Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
105 "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest2,
106 (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[1], GetLastError());
107 LeaveCriticalSection(&CriticalSection);
108
109 dwRet = ResumeThread(hThread[0]);
110 if (-1 == dwRet)
111 {
112 Trace("PALSUITE ERROR: ResumeThread(%p) call failed.\n"
113 "GetLastError returned '%d'.\n", hThread[0],
114 GetLastError());
115 }
116
117 dwRet = WaitForSingleObject(hThread[0], 10000);
118 if (WAIT_OBJECT_0 == dwRet)
119 {
120 Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
121 "failed. '%d' was returned instead of the expected '%d'.\n"
122 "GetLastError returned '%d'.\n", hThread[0], 10000, dwRet,
123 WAIT_OBJECT_0, GetLastError());
124 }
125
126 if (0 == CloseHandle(hThread[0]))
127 {
128 Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
129 "GetLastError returned %d. Not failing tests.\n",
130 hThread[0], GetLastError());
131 }
132
133 DeleteCriticalSection(&CriticalSection);
134 Fail("");
135 }
136
137 /*
138 * Set other thread priorities to be higher than ours & Sleep to ensure
139 * we give up the processor.
140 */
141 dwRet = (DWORD) SetThreadPriority(hThread[0],
142 THREAD_PRIORITY_ABOVE_NORMAL);
143 if (0 == dwRet)
144 {
145 Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
146 "GetLastError returned %d", hThread[0],
147 THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
148 }
149
150 dwRet = (DWORD) SetThreadPriority(hThread[1],
151 THREAD_PRIORITY_ABOVE_NORMAL);
152 if (0 == dwRet)
153 {
154 Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
155 "GetLastError returned %d", hThread[1],
156 THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
157 }
158
159 dwRet = ResumeThread(hThread[0]);
160 if (-1 == dwRet)
161 {
162 Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
163 "GetLastError returned %d", hThread[0],
164 GetLastError() );
165 }
166
167 dwRet = ResumeThread(hThread[1]);
168 if (-1 == dwRet)
169 {
170 Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
171 "GetLastError returned %d", hThread[0],
172 GetLastError());
173 }
174
175 Sleep (0);
176
177 LeaveCriticalSection (&CriticalSection);
178
179 dwRet = WaitForSingleObject(hThread[0], 10000);
180 dwRet1 = WaitForSingleObject(hThread[1], 10000);
181
182 if ((WAIT_OBJECT_0 == dwRet) ||
183 (WAIT_OBJECT_0 == dwRet1))
184 {
185 if ((1 == flags[0] && 0 == flags[1]) ||
186 (0 == flags[0] && 1 == flags[1]))
187 {
188 bTestResult = PASS;
189 }
190 else
191 {
192 bTestResult = FAIL;
193 Trace ("PALSUITE ERROR: flags[%d] = {%d,%d}. These values are"
194 "inconsistent.\nCriticalSection test failed.\n",
195 NUM_BLOCKING_THREADS, flags[0], flags[1]);
196 }
197
198 /* Fail the test if both threads returned WAIT_OBJECT_0 */
199 if ((WAIT_OBJECT_0 == dwRet) && (WAIT_OBJECT_0 == dwRet1))
200 {
201 bTestResult = FAIL;
202 Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
203 "WaitForSingleObject(%p, %d)\nboth returned dwRet = '%d'\n"
204 "One should have returned WAIT_TIMEOUT ('%d').\n",
205 hThread[0], 10000, hThread[1], 10000, dwRet, WAIT_TIMEOUT);
206 }
207 }
208 else
209 {
210 bTestResult = FAIL;
211 Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
212 "WaitForSingleObject(%p, %d)\nReturned dwRet = '%d' and\n"
213 "dwRet1 = '%d' respectively.\n", hThread[0], 10000, hThread[1],
214 10000, dwRet, dwRet1);
215 }
216
217 if (WAIT_OBJECT_0 == dwRet)
218 {
219 if (0 == CloseHandle(hThread[0]))
220 {
221 Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
222 "GetLastError returned %d. Not failing tests.\n",
223 hThread[0], GetLastError());
224 }
225 }
226 if (WAIT_OBJECT_0 == dwRet1)
227 {
228 if (0 == CloseHandle(hThread[1]))
229 {
230 Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
231 "GetLastError returned %d. Not failing tests.\n",
232 hThread[1], GetLastError());
233 }
234 }
235
236 /* Leaking the CS on purpose, since there is still a thread
237 waiting on it */
238
239 PAL_TerminateEx(bTestResult);
240 return (bTestResult);
241}
242