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/test2/test2.c
8**
9** Purpose: Test that we are able to nest critical section calls.
10** The initial thread makes a call to EnterCriticalSection once,
11** blocking on a CRITICAL_SECTION object and creates a new thread.
12** The newly created thread blocks on the same CRITICAL_SECTION object.
13** The first thread now makes a call to LeaveCriticalSection.
14** Test to see that the new thread doesn't get unblocked.
15**
16** Dependencies: CreateThread
17** InitializeCriticalSection
18** EnterCriticalSection
19** LeaveCriticalSection
20** DeleteCriticalSection
21** WaitForSingleObject
22**
23
24**
25**=========================================================*/
26
27#include <palsuite.h>
28
29CRITICAL_SECTION CriticalSection;
30
31volatile BOOL t0_tflag = FAIL; /* thread 0 timeout flag */
32volatile BOOL t1_aflag = FAIL; /* thread 1 access flag */
33volatile BOOL t1_cflag = FAIL; /* thread 1 critical section flag */
34volatile BOOL bTestResult = FAIL;
35
36DWORD PALAPI Thread(LPVOID lpParam)
37{
38 t1_aflag = PASS;
39 EnterCriticalSection(&CriticalSection);
40 t1_cflag = PASS;
41 LeaveCriticalSection(&CriticalSection);
42 return 0;
43}
44
45int __cdecl main (int argc, char **argv)
46{
47 HANDLE hThread;
48 DWORD dwThreadId;
49 DWORD dwRet;
50
51 if(0 != (PAL_Initialize(argc, argv)))
52 {
53 return (bTestResult);
54 }
55
56 /*
57 * Create critical section object and enter it
58 */
59 InitializeCriticalSection ( &CriticalSection );
60 EnterCriticalSection(&CriticalSection);
61
62 /*
63 * Create a suspended thread
64 */
65 hThread = CreateThread(NULL,
66 0,
67 &Thread,
68 (LPVOID) NULL,
69 CREATE_SUSPENDED,
70 &dwThreadId);
71
72 if (hThread == NULL)
73 {
74 Trace("PALSUITE ERROR: CreateThread call failed. GetLastError "
75 "returned %d.\n", GetLastError());
76 LeaveCriticalSection(&CriticalSection);
77 DeleteCriticalSection(&CriticalSection);
78 Fail("");
79 }
80
81 EnterCriticalSection(&CriticalSection);
82 /*
83 * Set priority of the thread to greater than that of the currently
84 * running thread so it is guaranteed to run.
85 */
86 dwRet = (DWORD) SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
87
88 if (0 == dwRet)
89 {
90 Trace("PALSUITE ERROR: SetThreadPriority (%p, %d) call failed.\n"
91 "GetLastError returned %d.\n", hThread,
92 THREAD_PRIORITY_NORMAL, GetLastError());
93 LeaveCriticalSection(&CriticalSection);
94 CloseHandle(hThread);
95 DeleteCriticalSection(&CriticalSection);
96 Fail("");
97 }
98
99 dwRet = ResumeThread(hThread);
100
101 if (-1 == dwRet)
102 {
103 Trace("PALSUITE ERROR: ResumeThread(%p) call failed.\nGetLastError "
104 "returned %d.\n", hThread, GetLastError());
105 LeaveCriticalSection(&CriticalSection);
106 CloseHandle(hThread);
107 DeleteCriticalSection(&CriticalSection);
108 Fail("");
109 }
110 /*
111 * Sleep until we know the thread has been invoked. This sleep in
112 * combination with the higher priority of the other thread should
113 * guarantee both threads block on the critical section.
114 */
115 while (t1_aflag == FAIL)
116 {
117 Sleep(1);
118 }
119
120 LeaveCriticalSection(&CriticalSection);
121
122 switch ((WaitForSingleObject(
123 hThread,
124 10000))) /* Wait 10 seconds */
125 {
126 case WAIT_OBJECT_0:
127 /* Object (thread) is signaled */
128 LeaveCriticalSection(&CriticalSection);
129 CloseHandle(hThread);
130 DeleteCriticalSection(&CriticalSection);
131 Fail("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
132 "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
133 "WAIT_OBJECT_0 ('%d').\nA nested LeaveCriticalSection(%p) "
134 "call released both threads that were waiting on it!\n",
135 hThread, 10000, WAIT_TIMEOUT, WAIT_OBJECT_0, &CriticalSection);
136 break;
137 case WAIT_ABANDONED:
138 /*
139 * Object was mutex object whose owning
140 * thread has terminated. Shouldn't occur.
141 */
142 Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
143 "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
144 "WAIT_ABANDONED ('%d').\nGetLastError returned '%d'\n",
145 hThread, 10000, WAIT_TIMEOUT, WAIT_ABANDONED, GetLastError());
146 LeaveCriticalSection(&CriticalSection);
147 CloseHandle(hThread);
148 DeleteCriticalSection(&CriticalSection);
149 Fail("");
150 break;
151 case WAIT_FAILED: /* WaitForSingleObject function failed */
152 Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
153 "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
154 "WAIT_FAILED ('%d').\nGetLastError returned '%d'\n",
155 hThread, 10000, WAIT_TIMEOUT, WAIT_FAILED, GetLastError());
156 LeaveCriticalSection(&CriticalSection);
157 CloseHandle(hThread);
158 DeleteCriticalSection(&CriticalSection);
159 Fail("");
160 break;
161 case WAIT_TIMEOUT:
162 /*
163 * We expect this thread to timeout waiting for the
164 * critical section object to become available.
165 */
166 t0_tflag = PASS;
167 break;
168 }
169
170 LeaveCriticalSection(&CriticalSection);
171
172 if (WAIT_OBJECT_0 != WaitForSingleObject (hThread, 10000))
173 {
174 if (0 == CloseHandle(hThread))
175 {
176 Trace("PALSUITE ERROR: CloseHandle(%p) call failed.\n"
177 "WaitForSingleObject(%p,%d) should have returned "
178 "WAIT_OBJECT_0 ('%d').\nBoth calls failed. "
179 "Deleted CRITICAL_SECTION object which likely means\n"
180 "thread %p is now in an undefined state. GetLastError "
181 "returned '%d'.\n", hThread, hThread, 10000, WAIT_OBJECT_0,
182 hThread, GetLastError());
183 DeleteCriticalSection(&CriticalSection);
184 Fail("");
185 }
186 else
187 {
188 Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
189 "returned WAIT_OBJECT_0 ('%d').\n GetLastError returned "
190 "'%d'.\n", hThread, hThread, 10000, WAIT_OBJECT_0,
191 hThread, GetLastError());
192 DeleteCriticalSection(&CriticalSection);
193 Fail("");
194 }
195 }
196
197 if (0 == CloseHandle(hThread))
198 {
199 Trace("PALSUITE ERROR: CloseHandle(%p) call failed.\n"
200 "Deleted CRITICAL_SECTION object which likely means\n"
201 "thread %p is now in an undefined state. GetLastError "
202 "returned '%d'.\n", hThread, hThread, GetLastError());
203 DeleteCriticalSection(&CriticalSection);
204 Fail("");
205
206 }
207 DeleteCriticalSection(&CriticalSection);
208 /*
209 * Ensure both thread 0 experienced a wait timeout and thread 1
210 * accessed the critical section or fail the test, otherwise pass it.
211 */
212 if ((t0_tflag == FAIL) || (t1_cflag == FAIL))
213 {
214 Trace("PALSUITE ERROR: Thread 0 returned %d when %d was expected.\n"
215 "Thread 1 returned %d when %d was expected.\n", t0_tflag,
216 PASS, t1_cflag, PASS);
217 bTestResult=FAIL;
218 }
219 else
220 {
221 bTestResult=PASS;
222 }
223
224 PAL_TerminateEx(bTestResult);
225 return (bTestResult);
226}
227