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: test4.c (DuplicateHandle) |
8 | ** |
9 | ** Purpose: Tests the PAL implementation of the DuplicateHandle function. |
10 | ** This test duplication of a Mutex handle. The test will comprise |
11 | ** of creating a Mutex and its duplicate and create a thread that |
12 | ** will get ownership. Another thread will be create that will |
13 | ** attempt to get ownership of the duplicate Mutex, this will |
14 | ** fail, since the Mutex is owned by another thread. The Mutex |
15 | ** will be released and then the thread will attempt to get |
16 | ** ownership of the duplicate Mutex, this will succeed. |
17 | ** |
18 | ** |
19 | **===================================================================*/ |
20 | #include <palsuite.h> |
21 | |
22 | enum wait_results |
23 | { |
24 | WR_WAITING, |
25 | WR_GOT_MUTEX, |
26 | WR_TIMED_OUT, |
27 | WR_RELEASED |
28 | }; |
29 | |
30 | |
31 | volatile int t1_result=WR_WAITING; |
32 | volatile int t2_result=WR_WAITING; |
33 | |
34 | |
35 | DWORD PALAPI ThreadTest1(LPVOID lpParam) |
36 | { |
37 | DWORD dwWait; |
38 | |
39 | dwWait = WaitForSingleObject((HANDLE)lpParam, 0); |
40 | if (dwWait == WAIT_OBJECT_0) |
41 | { |
42 | /* tell the main thread we got the mutex */ |
43 | t1_result=WR_GOT_MUTEX; |
44 | |
45 | /* wait for main thread to tell us to release the mutex */ |
46 | while(WR_GOT_MUTEX == t1_result) |
47 | Sleep(1); |
48 | ReleaseMutex((HANDLE)lpParam); |
49 | |
50 | /* tell the main thread we released the mutex */ |
51 | t1_result = WR_RELEASED; |
52 | } |
53 | else |
54 | { |
55 | t1_result = WR_TIMED_OUT; |
56 | } |
57 | return 0; |
58 | } |
59 | |
60 | DWORD PALAPI ThreadTest2(LPVOID lpParam) |
61 | { |
62 | DWORD dwWait; |
63 | |
64 | dwWait = WaitForSingleObject((HANDLE)lpParam, 0 ); |
65 | if (dwWait == WAIT_OBJECT_0) |
66 | { |
67 | ReleaseMutex((HANDLE)lpParam); |
68 | t2_result = WR_GOT_MUTEX; |
69 | } |
70 | else |
71 | { |
72 | t2_result = WR_TIMED_OUT; |
73 | } |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | |
79 | int __cdecl main(int argc, char **argv) |
80 | { |
81 | |
82 | HANDLE hDupMutex; |
83 | HANDLE hMutex; |
84 | HANDLE hThread; |
85 | HANDLE hThread2; |
86 | BOOL bDupHandle=FALSE; |
87 | DWORD dwThreadId = 0; |
88 | |
89 | if ((PAL_Initialize(argc,argv)) != 0) |
90 | { |
91 | return(FAIL); |
92 | } |
93 | |
94 | /*Create Mutex without ownership*/ |
95 | hMutex = CreateMutexW(NULL, // no security attributes |
96 | FALSE, // initially not owned |
97 | NULL); // name of mutex |
98 | if (hMutex == NULL) |
99 | { |
100 | Fail("ERROR:%u: Unable to create mutex\n" , |
101 | GetLastError()); |
102 | } |
103 | |
104 | /*Create Duplicate of the Mutex above*/ |
105 | bDupHandle = DuplicateHandle(GetCurrentProcess(), |
106 | hMutex, |
107 | GetCurrentProcess(), |
108 | &hDupMutex, |
109 | GENERIC_READ|GENERIC_WRITE, |
110 | FALSE, |
111 | DUPLICATE_SAME_ACCESS); |
112 | if (!bDupHandle) |
113 | { |
114 | Trace("ERROR:%u: Created the duplicate handle to " |
115 | "closed event handle hMutex=0x%lx\n" , |
116 | GetLastError(), |
117 | hMutex); |
118 | CloseHandle(hMutex); |
119 | Fail("" ); |
120 | } |
121 | |
122 | /*Create a thread to test the Mutex*/ |
123 | hThread = CreateThread(NULL, |
124 | 0, |
125 | &ThreadTest1, |
126 | hMutex, |
127 | 0, |
128 | &dwThreadId); |
129 | if (hThread == NULL) |
130 | { |
131 | Trace("ERROR:%u: unable to create thread\n" , |
132 | GetLastError()); |
133 | CloseHandle(hMutex); |
134 | CloseHandle(hDupMutex); |
135 | Fail("" ); |
136 | } |
137 | |
138 | /* wait until thread has taken the mutex */ |
139 | while (WR_WAITING == t1_result) |
140 | Sleep(1); |
141 | |
142 | if(WR_TIMED_OUT == t1_result) |
143 | { |
144 | Trace("ERROR: %u: thread 1 couldn't acquire the mutex\n" ); |
145 | CloseHandle(hMutex); |
146 | CloseHandle(hDupMutex); |
147 | CloseHandle(hThread); |
148 | Fail("" ); |
149 | } |
150 | |
151 | /*Create a second thread to use the duplicate Mutex*/ |
152 | /*This should fail since the Mutex is owned hThread*/ |
153 | hThread2 = CreateThread(NULL, |
154 | 0, |
155 | &ThreadTest2, |
156 | hDupMutex, |
157 | 0, |
158 | &dwThreadId); |
159 | |
160 | if (hThread2 == NULL) |
161 | { |
162 | Trace("ERROR:%u: unable to create thread\n" , |
163 | GetLastError()); |
164 | CloseHandle(hMutex); |
165 | CloseHandle(hDupMutex); |
166 | CloseHandle(hThread); |
167 | Fail("" ); |
168 | } |
169 | |
170 | /* wait until thread has tried to take the mutex */ |
171 | while (WR_WAITING == t2_result) |
172 | Sleep(1); |
173 | |
174 | if (WR_TIMED_OUT != t2_result ) |
175 | { |
176 | Trace("ERROR:%u: Able to take mutex %#x while its duplicate %#x is " |
177 | "held\n" , hDupMutex, hMutex); |
178 | CloseHandle(hMutex); |
179 | CloseHandle(hDupMutex); |
180 | CloseHandle(hThread); |
181 | CloseHandle(hThread2); |
182 | Fail("" ); |
183 | } |
184 | |
185 | /* reset second thread status */ |
186 | t2_result = WR_WAITING; |
187 | |
188 | /* tell thread 1 to release the mutex */ |
189 | t1_result = WR_WAITING; |
190 | |
191 | /* wait for thread 1 to release the mutex */ |
192 | while (WR_WAITING == t1_result) |
193 | Sleep(1); |
194 | |
195 | CloseHandle(hThread2); |
196 | |
197 | /*Re-Create the second thread to reuse the duplicated Mutex*/ |
198 | /*This test should pass, the Mutex has since been released*/ |
199 | hThread2 = CreateThread(NULL, |
200 | 0, |
201 | &ThreadTest2, |
202 | hDupMutex, |
203 | 0, |
204 | &dwThreadId); |
205 | |
206 | if (hThread2 == NULL) |
207 | { |
208 | Trace("ERROR:%u: unable to create thread\n" , |
209 | GetLastError()); |
210 | CloseHandle(hMutex); |
211 | CloseHandle(hDupMutex); |
212 | CloseHandle(hThread); |
213 | Fail("" ); |
214 | } |
215 | |
216 | /* wait until thread has taken the mutex */ |
217 | while (WR_WAITING == t2_result) |
218 | Sleep(1); |
219 | |
220 | if (WR_GOT_MUTEX != t2_result ) |
221 | { |
222 | Trace("ERROR:%u: Unable to take mutex %#x after its duplicate %#x was " |
223 | "released\n" , hDupMutex, hMutex); |
224 | CloseHandle(hMutex); |
225 | CloseHandle(hDupMutex); |
226 | CloseHandle(hThread); |
227 | CloseHandle(hThread2); |
228 | Fail("" ); |
229 | } |
230 | |
231 | /*Cleanup.*/ |
232 | CloseHandle(hMutex); |
233 | CloseHandle(hDupMutex); |
234 | CloseHandle(hThread); |
235 | CloseHandle(hThread2); |
236 | |
237 | PAL_Terminate(); |
238 | return (PASS); |
239 | } |
240 | |