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/test1/CreateMutexW.c
8**
9** Purpose: This test case tests whether a Mutex object created
10** with CreateMutex really works by mutually excluding
11** threads from accessing a data structure at the same
12** time. Here we have a buffer that can be filled or
13** emptied, we use a Mutex object to ensure that one
14** operation cannot be started until the other is
15** finished. If one operation detects that the other
16** has not finished, it fails. There is a Producer
17** thread which will try to fill the buffer 25 times,
18** and a consumer thread which try to empty the buffer
19** 25 times. If either the fill or empty operations
20** fails because the Mutex failed to mutually exclude
21** them, the corresponding thread will set an error
22** flag and return. This will cause the test case to
23** fail.
24**
25** To increase the probability of identifying problems,
26** the Fill opeartion has been slowed dowm with a call
27** to Sleep. This ensures that one operation will try
28** to access the shared buffer while the other is in
29** progress.
30**
31** NOTE: this test case also serves as a test case for
32** WaitForSingleObject.
33**
34**
35** Dependencies: CreateThread
36** ReleaseMutex
37** WaitForSingleObject
38** WaitForMultipleObjects
39** Sleep
40** memset
41**
42
43**
44**=========================================================*/
45
46#define UNICODE
47#include <palsuite.h>
48
49/* Define some values that we will using many times */
50#define MAIN_BUF_SIZE 40
51#define NUM_OF_CYCLES 40
52
53/* Buffer Operation return codes */
54#define OP_OK 0
55#define OP_ERR 1
56#define OP_NONE 2
57
58
59HANDLE hMutex; /* handle to mutex */
60
61BOOL bProdErr; /* Producer error Flag */
62BOOL bConErr; /* Consumer error Flag */
63
64/* Test Buffer */
65char Buffer[MAIN_BUF_SIZE];
66
67/*
68 * EmptyBuffer implements the empty operation for test buffer.
69 */
70int
71EmptyBuffer()
72{
73 int i;
74
75 if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
76 {
77 Fail("ERROR: WaitForSingleObject failed.\n");
78 }
79
80 /* Check to see if the buffer is already completely empty */
81 for (i=0; i<MAIN_BUF_SIZE && Buffer[i] == 0; i++);
82 if (i == MAIN_BUF_SIZE)
83 {
84 /* Its empty so just return */
85 if (ReleaseMutex(hMutex) == FALSE)
86 {
87 Fail("ERROR: ReleaseMutex Failed.\n");
88 }
89 return OP_NONE;
90 }
91
92 /* Its not empty so we must empty it. */
93 for (i=0; i<MAIN_BUF_SIZE; i++)
94 {
95 /* Check for empty slots if we find one then the */
96 /* fill operation did no finish. return an error */
97 if (Buffer[i] == 0)
98 {
99 if (ReleaseMutex(hMutex) == FALSE)
100 {
101 Fail("ERROR: ReleaseMutex Failed.\n");
102 }
103 return OP_ERR;
104 }
105
106 Buffer[i] = 0;
107 }
108
109 if (ReleaseMutex(hMutex) == FALSE)
110 {
111 Fail("ERROR: ReleaseMutex Failed.\n");
112 }
113 return OP_OK;
114}
115
116/*
117 * FillBuffer implements the fill operation for test buffer.
118 */
119int
120FillBuffer()
121{
122 int i;
123
124 if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
125 {
126 Fail("ERROR: WaitForSingleObject failed.\n");
127 }
128
129 /* Check to see if the buffer is already completely full */
130 for (i=0; i<MAIN_BUF_SIZE && Buffer[i] != 0; i++);
131 if (i == MAIN_BUF_SIZE)
132 {
133 /* Its full so just return */
134 if (ReleaseMutex(hMutex) == FALSE)
135 {
136 Fail("ERROR: ReleaseMutex Failed.\n");
137 }
138 return OP_NONE;
139 }
140
141 /* Its not full so we must fill it. */
142 for (i=0; i<MAIN_BUF_SIZE; i++)
143 {
144 /* Check for filled slots if we find one then the */
145 /* empty operation did not finish. return an error */
146 if (Buffer[i] == 1)
147 {
148 if (ReleaseMutex(hMutex) == FALSE)
149 {
150 Fail("ERROR: ReleaseMutex Failed.\n");
151 }
152 return OP_ERR;
153 }
154
155 Buffer[i] = 1;
156 Sleep(10);
157 }
158
159 if (ReleaseMutex(hMutex) == FALSE)
160 {
161 Fail("ERROR: ReleaseMutex Failed.\n");
162 }
163 return OP_OK;
164}
165
166
167
168
169/*
170 * Producer thread function.
171 */
172DWORD PALAPI Producer(LPVOID lpParam)
173{
174 int n = 0;
175 int ret;
176
177 while (n < NUM_OF_CYCLES)
178 {
179 if (bConErr == TRUE)
180 {
181 /* The consumer ran into an error so we'll stop */
182 return 0;
183 }
184
185 ret = FillBuffer();
186
187 if (ret == OP_OK)
188 {
189 n++;
190 }
191 else if (ret == OP_ERR)
192 {
193 bProdErr = TRUE;
194 return 0;
195 }
196 }
197
198 return 0;
199}
200
201/*
202 * Consumer thread function.
203 */
204DWORD PALAPI Consumer( LPVOID lpParam )
205{
206 int n = 0;
207 int ret;
208
209 while (n < NUM_OF_CYCLES)
210 {
211 if (bProdErr == TRUE)
212 {
213 /* The consumer ran into an error so we'll stop */
214 return 0;
215 }
216
217 ret = EmptyBuffer();
218
219 if (ret == OP_OK)
220 {
221 n++;
222 }
223 else if (ret == OP_ERR)
224 {
225 bConErr = TRUE;
226 return 0;
227 }
228 }
229
230 return 0;
231}
232
233
234int __cdecl main (int argc, char **argv)
235{
236 DWORD dwThreadId;
237 DWORD dwWaitRet;
238
239 HANDLE hThread1; /* handle to consumer thread */
240 HANDLE hThread2; /* handle to producer thread */
241 HANDLE handleArray[2];
242
243
244 if(0 != (PAL_Initialize(argc, argv)))
245 {
246 return ( FAIL );
247 }
248
249 /* Initialize our error flags */
250 bProdErr = FALSE;
251 bConErr = FALSE;
252
253 /*
254 * Initialize the Buffer to be empty
255 */
256 memset(Buffer, 0, MAIN_BUF_SIZE);
257
258 /*
259 * Create Mutex
260 */
261 hMutex = CreateMutexW (NULL, FALSE, NULL);
262
263 if (NULL == hMutex)
264 {
265 Fail("hMutex = CreateMutexW() - returned NULL\n"
266 "Failing Test.\nGetLastError returned %u\n", GetLastError());
267 }
268
269
270 /*
271 * Create the Producer thread
272 */
273 hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Producer,
274 0, 0, &dwThreadId);
275
276 if ( NULL == hThread1 )
277 {
278 CloseHandle(hMutex);
279
280 Fail("CreateThread() returned NULL. Failing test.\n"
281 "GetLastError returned %u\n", GetLastError());
282 }
283
284 /*
285 * Create the Consumer thread
286 */
287 hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Consumer,
288 0, 0, &dwThreadId);
289
290 if ( NULL == hThread2 )
291 {
292 CloseHandle(hMutex);
293
294 /* Set the error flag and give thread1 some time to exit */
295 bConErr = FALSE;
296 Sleep(250);
297
298 Fail("CreateThread() returned NULL. Failing test.\n"
299 "GetLastError returned %u\n", GetLastError());
300 }
301
302 /*
303 * Wait for both threads to complete (Max 45 Seconds)
304 */
305 handleArray[0] = hThread1;
306 handleArray[1] = hThread2;
307 dwWaitRet = WaitForMultipleObjects (2, handleArray, TRUE, 450000);
308 if (dwWaitRet == WAIT_FAILED)
309 {
310 Fail("ERROR: WaitForMultipleObjects failed.\n");
311 }
312 else if (dwWaitRet == WAIT_TIMEOUT)
313 {
314 /* Set the error flags and give the threads some time to exit */
315 bProdErr = FALSE;
316 bConErr = FALSE;
317 Sleep(250);
318
319 Fail("ERROR: Timeout interval exceeded.\n");
320 }
321
322 /*
323 * Clean up
324 */
325 if (CloseHandle(hThread1) == FALSE ||
326 CloseHandle(hThread2) == FALSE ||
327 CloseHandle(hMutex) == FALSE)
328 {
329 Fail("ERROR: CloseHandle failed.\n");
330 }
331
332
333 /*
334 * Check our error flags
335 */
336 if (bProdErr == TRUE || bConErr == TRUE)
337 {
338 Fail("ERROR: A collision occurred, so the mutex failed.\n");
339 }
340
341 PAL_Terminate();
342 return ( PASS );
343
344}
345