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: CreateMutexW_ReleaseMutex/test2/CreateMutexW.c
8**
9** Purpose: This test case tests the following things
10** - Creation of named Mutexes
11** - Creating multiple handles to a single named Mutex
12** - Ensuring that these handles work interchangeably
13** - Setting bInitialOwnerFlag to TRUE will cause the
14** initial call to a Wait function on the same Mutex
15** to actually wait.
16** - Waiting on a Mutex that a thread already owns does
17** not block.
18** - Create Named mutex with empty string ("")
19** - Create Named mutex with string of MAX_LONGPATH length
20** - Calling RelaseMutex with invalid Mutex handles and
21** valid but unowned Mutexes.
22**
23** Dependencies: CreateThread
24** ReleaseMutex
25** WaitForSingleObject
26** CloseHandle
27** Sleep
28** memset
29**
30
31**
32**=========================================================*/
33
34#define UNICODE
35#include <palsuite.h>
36
37const char *szMutex = "MyMutex";
38const char *szEmpty = "";
39
40/* Function Prototypes */
41BOOL TestNamedMutex(const char *szMutexName);
42DWORD NamedMutexThread(LPVOID lpParam);
43BOOL NegativeReleaseMutexTests();
44
45struct ThreadData
46{
47 HANDLE hMutex;
48 BOOL bReturnCode;
49};
50typedef struct ThreadData THREADDATA;
51
52
53int __cdecl main (int argc, char **argv)
54{
55 BOOL bFailures = FALSE;
56 char *szMaxPath;
57
58 if(0 != (PAL_Initialize(argc, argv)))
59 {
60 return ( FAIL );
61 }
62
63
64 /*
65 * Test named Mutexes with ordinary string
66 */
67
68 if (!TestNamedMutex(szMutex))
69 {
70 bFailures = TRUE;
71 }
72
73
74 /*
75 * Test named Mutexes with empty ("") string
76 */
77
78 if (!TestNamedMutex(szEmpty))
79 {
80 bFailures = TRUE;
81 }
82
83
84 /*
85 * Test named Mutexes with string of length MAX_LONGPATH
86 */
87
88 szMaxPath = (char *)malloc(MAX_LONGPATH+2);
89 memset(szMaxPath, 'A', MAX_LONGPATH-60);
90 szMaxPath[MAX_LONGPATH-60] = 0;
91
92 if (!TestNamedMutex(szMaxPath))
93 {
94 bFailures = TRUE;
95 }
96
97 free(szMaxPath);
98
99
100 /*
101 * Run some negative tests on ReleaseMutex
102 */
103
104 if (!NegativeReleaseMutexTests())
105 {
106 bFailures = TRUE;
107 }
108
109
110 /*
111 * If there were any failures, then abort with a call to Fail
112 */
113
114 if (bFailures == TRUE)
115 {
116 Fail("ERROR: There some failures in the Mutex tests.\n");
117 }
118
119 PAL_Terminate();
120 return ( PASS );
121}
122
123
124/*
125 * Testing Function
126 *
127 * Try to get multiple handles to a named Mutex and test
128 * to make sure they actually refer to same Mutex object.
129 */
130BOOL TestNamedMutex(const char *szMutexName)
131{
132 DWORD dwData;
133 HANDLE hMutex1;
134 HANDLE hMutex2;
135 HANDLE hThread;
136 WCHAR *swzMutexName;
137 THREADDATA threadData;
138
139 /* Convert the Mutex name to wide characters */
140 swzMutexName = convert((char *)szMutexName);
141
142 /* Create a mutex and take ownership immediately */
143 hMutex1 = CreateMutexW (NULL, TRUE, swzMutexName);
144
145 if (NULL == hMutex1)
146 {
147 Trace("ERROR: CreateMutex #1 failed. GetLastError returned %u\n",
148 GetLastError());
149 free(swzMutexName);
150 return FALSE;
151 }
152
153 /* Try to wait on the Mutex we just created. We should not block. */
154 if (WaitForSingleObject(hMutex1, 1000) == WAIT_TIMEOUT)
155 {
156 Trace("WaitForSingleObject blocked on a Mutex that we owned.\n");
157 free(swzMutexName);
158 return FALSE;
159 }
160 /* We have to call ReleaseMutex here because of the Wait */
161 if (ReleaseMutex(hMutex1) == FALSE)
162 {
163 Trace("ReleaseMutex Failed.\n");
164 return FALSE;
165 }
166
167 /* Get a second handle to the same mutex */
168 hMutex2 = CreateMutexW (NULL, FALSE, swzMutexName);
169
170 if (NULL == hMutex2)
171 {
172 Trace("ERROR: CreateMutex #2 failed. GetLastError returned %u\n",
173 GetLastError());
174 free(swzMutexName);
175 return FALSE;
176 }
177
178 /* Get rid of the wide character string */
179 free(swzMutexName);
180
181 /*
182 * Create a thread that will Wait on the second handle.
183 */
184 threadData.hMutex = hMutex2;
185 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NamedMutexThread,
186 (LPVOID)&threadData, 0, &dwData);
187
188 if (NULL == hThread)
189 {
190 Trace("ERROR: CreateThread failed. GetLastError returned %u\n",
191 GetLastError());
192 return FALSE;
193 }
194
195 /* Give the thread a little time to execute & wait*/
196 Sleep(500);
197
198 /* Signal the the first handle */
199 if (ReleaseMutex(hMutex1) == FALSE)
200 {
201 Trace("ReleaseMutex Failed.\n");
202 return FALSE;
203 }
204
205 /* Give the thread some time to finish */
206 Sleep(2000);
207
208 /* Clean Up */
209 if (CloseHandle(hMutex1) == FALSE ||
210 CloseHandle(hMutex2) == FALSE ||
211 CloseHandle(hThread) == FALSE)
212 {
213 Trace("ERROR: CloseHandle failed.\n");
214 return FALSE;
215 }
216
217 /* Check the return code to see if signalling the first */
218 /* Mutex handle woke up the thread which was Waiting on */
219 /* the second handle. */
220 if (threadData.bReturnCode != FALSE)
221 {
222 Trace("ERROR: The handles did not refer to the same Mutex object.\n");
223 return FALSE;
224 }
225
226 return TRUE;
227}
228
229
230/*
231 * Thread function used with above testing function.
232 */
233DWORD NamedMutexThread(LPVOID lpParam)
234{
235 BOOL bTimedOut = FALSE;
236 THREADDATA *lpThreadData = (THREADDATA *)lpParam;
237
238 /* Wait on the Mutex that was passed to us */
239 if (WaitForSingleObject(lpThreadData->hMutex, 10000) == WAIT_TIMEOUT)
240 {
241 /* The Mutex was not signaled in the allotted time */
242 bTimedOut = TRUE;
243 }
244 if (ReleaseMutex(lpThreadData->hMutex) == FALSE)
245 {
246 Trace("ERROR: ReleaseMutex failed.\n");
247 lpThreadData->bReturnCode = FALSE;
248 return 0;
249 }
250
251 /* Indicate whether we timed out Waiting on the Mutex */
252 lpThreadData->bReturnCode = bTimedOut;
253
254 return 0;
255}
256
257
258/*
259 * Testing Function
260 *
261 * Try some negative tests on ReleaseMutex
262 */
263BOOL NegativeReleaseMutexTests()
264{
265 HANDLE hMutex;
266 BOOL bRet;
267 BOOL bResults = TRUE;
268
269
270 /*
271 * Try calling ReleaseMutex on a null handle
272 */
273 hMutex = 0;
274 bRet = ReleaseMutex(hMutex);
275
276 if (bRet != 0)
277 {
278 Trace("Error: ReleaseMutex accepted null handle.\n");
279 bResults = FALSE;
280 }
281
282
283 /*
284 * Try calling ReleaseMutex on an handle that we don't own
285 */
286 hMutex = CreateMutexW (NULL, TRUE, NULL);
287 if (hMutex == 0)
288 {
289 Trace("Error: CreateMutex failed.\n");
290 bResults = FALSE;
291 }
292
293 bRet = ReleaseMutex(hMutex);
294 bRet = ReleaseMutex(hMutex);
295
296 if (bRet != FALSE)
297 {
298 Trace("Error: ReleaseMutex accepted unowned handle.\n");
299 bResults = FALSE;
300 }
301
302 if (CloseHandle(hMutex) == FALSE)
303 {
304 Trace("Error: CloseHandle failed.\n");
305 bResults = FALSE;
306 }
307
308
309
310 /*
311 * Try calling ReleaseMutex on an handle that has been closed
312 */
313 hMutex = CreateMutexW (NULL, TRUE, NULL);
314 if (hMutex == 0)
315 {
316 Trace("Error: CreateMutex failed.\n");
317 bResults = FALSE;
318 }
319
320 if (ReleaseMutex(hMutex) == FALSE)
321 {
322 Trace("Error: ReleaseMutex failed.\n");
323 bResults = FALSE;
324 }
325 if (CloseHandle(hMutex) == FALSE)
326 {
327 Trace("Error: CloseHandle failed.\n");
328 bResults = FALSE;
329 }
330
331 bRet = ReleaseMutex(hMutex);
332
333 if (bRet != FALSE)
334 {
335 Trace("Error: ReleaseMutex accepted invalid handle.\n");
336 bResults = FALSE;
337 }
338
339 return bResults;
340}
341