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: CreateMutexA_ReleaseMutex/test2/CreateMutexA.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_LONGPATHPATH
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((void*)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 THREADDATA threadData;
137
138 /* Create a mutex and take ownership immediately */
139 hMutex1 = CreateMutexA (NULL, TRUE, szMutexName);
140
141 if (NULL == hMutex1)
142 {
143 Trace("ERROR: CreateMutexA #1 failed. GetLastError returned %u\n",
144 GetLastError());
145 return FALSE;
146 }
147
148 /* Try to wait on the Mutex we just created. We should not block. */
149 if (WaitForSingleObject(hMutex1, 1000) == WAIT_TIMEOUT)
150 {
151 Trace("WaitForSingleObject blocked on a Mutex that we owned.\n");
152 return FALSE;
153 }
154 /* We have to call ReleaseMutex here because of the Wait */
155 if (ReleaseMutex(hMutex1) == FALSE)
156 {
157 Trace("ReleaseMutex Failed.\n");
158 return FALSE;
159 }
160
161 /* Get a second handle to the same mutex */
162 hMutex2 = CreateMutexA (NULL, FALSE, szMutexName);
163
164 if (NULL == hMutex2)
165 {
166 Trace("ERROR: CreateMutex #2 failed. GetLastError returned %u\n",
167 GetLastError());
168 free((void*)szMutexName);
169 return FALSE;
170 }
171
172 /*
173 * Create a thread that will Wait on the second handle.
174 */
175 threadData.hMutex = hMutex2;
176 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NamedMutexThread,
177 (LPVOID)&threadData, 0, &dwData);
178
179 if (NULL == hThread)
180 {
181 Trace("ERROR: CreateThread failed. GetLastError returned %u\n",
182 GetLastError());
183 return FALSE;
184 }
185
186 /* Give the thread a little time to execute & wait*/
187 Sleep(500);
188
189 /* Signal the the first handle */
190 if (ReleaseMutex(hMutex1) == FALSE)
191 {
192 Trace("ReleaseMutex Failed.\n");
193 return FALSE;
194 }
195
196 /* Give the thread some time to finish */
197 Sleep(2000);
198
199 /* Clean Up */
200 if (CloseHandle(hMutex1) == FALSE ||
201 CloseHandle(hMutex2) == FALSE ||
202 CloseHandle(hThread) == FALSE)
203 {
204 Trace("ERROR: CloseHandle failed.\n");
205 return FALSE;
206 }
207
208 /* Check the return code to see if signalling the first */
209 /* Mutex handle woke up the thread which was Waiting on */
210 /* the second handle. */
211 if (threadData.bReturnCode != FALSE)
212 {
213 Trace("ERROR: The handles did not refer to the same Mutex object.\n");
214 return FALSE;
215 }
216
217 return TRUE;
218}
219
220
221/*
222 * Thread function used with above testing function.
223 */
224DWORD NamedMutexThread(LPVOID lpParam)
225{
226 BOOL bTimedOut = FALSE;
227 THREADDATA *lpThreadData = (THREADDATA *)lpParam;
228
229 /* Wait on the Mutex that was passed to us */
230 if (WaitForSingleObject(lpThreadData->hMutex, 10000) == WAIT_TIMEOUT)
231 {
232 /* The Mutex was not signaled in the allotted time */
233 bTimedOut = TRUE;
234 }
235 if (ReleaseMutex(lpThreadData->hMutex) == FALSE)
236 {
237 Trace("ERROR: ReleaseMutex failed.\n");
238 lpThreadData->bReturnCode = FALSE;
239 return 0;
240 }
241
242 /* Indicate whether we timed out Waiting on the Mutex */
243 lpThreadData->bReturnCode = bTimedOut;
244
245 return 0;
246}
247
248
249/*
250 * Testing Function
251 *
252 * Try some negative tests on ReleaseMutex
253 */
254BOOL NegativeReleaseMutexTests()
255{
256 HANDLE hMutex;
257 BOOL bRet;
258 BOOL bResults = TRUE;
259
260
261 /*
262 * Try calling ReleaseMutex on a null handle
263 */
264 hMutex = 0;
265 bRet = ReleaseMutex(hMutex);
266
267 if (bRet != 0)
268 {
269 Trace("Error: ReleaseMutex accepted null handle.\n");
270 bResults = FALSE;
271 }
272
273
274 /*
275 * Try calling ReleaseMutex on an handle that we don't own
276 */
277 hMutex = CreateMutexA (NULL, TRUE, NULL);
278 if (hMutex == 0)
279 {
280 Trace("Error: CreateMutex failed.\n");
281 bResults = FALSE;
282 }
283
284 bRet = ReleaseMutex(hMutex);
285 bRet = ReleaseMutex(hMutex);
286
287 if (bRet != FALSE)
288 {
289 Trace("Error: ReleaseMutex accepted unowned handle.\n");
290 bResults = FALSE;
291 }
292
293 if (CloseHandle(hMutex) == FALSE)
294 {
295 Trace("Error: CloseHandle failed.\n");
296 bResults = FALSE;
297 }
298
299
300
301 /*
302 * Try calling ReleaseMutex on an handle that has been closed
303 */
304 hMutex = CreateMutexA (NULL, TRUE, NULL);
305 if (hMutex == 0)
306 {
307 Trace("Error: CreateMutex failed.\n");
308 bResults = FALSE;
309 }
310
311 if (ReleaseMutex(hMutex) == FALSE)
312 {
313 Trace("Error: ReleaseMutex failed.\n");
314 bResults = FALSE;
315 }
316 if (CloseHandle(hMutex) == FALSE)
317 {
318 Trace("Error: CloseHandle failed.\n");
319 bResults = FALSE;
320 }
321
322 bRet = ReleaseMutex(hMutex);
323
324 if (bRet != FALSE)
325 {
326 Trace("Error: ReleaseMutex accepted invalid handle.\n");
327 bResults = FALSE;
328 }
329
330 return bResults;
331}
332