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
22enum wait_results
23{
24 WR_WAITING,
25 WR_GOT_MUTEX,
26 WR_TIMED_OUT,
27 WR_RELEASED
28};
29
30
31volatile int t1_result=WR_WAITING;
32volatile int t2_result=WR_WAITING;
33
34
35DWORD 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
60DWORD 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
79int __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