| 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: CriticalSectionFunctions/test3/test3.c |
| 8 | ** |
| 9 | ** Purpose: Create two threads to exercise TryEnterCriticalSection |
| 10 | ** and EnterCriticalSection. TryEnterCriticalSection acquires |
| 11 | ** and holds a CRITICAL_SECTION object. Another call to |
| 12 | ** TryEnterCriticalSection is made from a different thread, at |
| 13 | ** this time, to establish a call to TryEnterCriticalSection |
| 14 | ** will return immediatly and to establish |
| 15 | ** TryEnterCriticalSection returns the proper value when it |
| 16 | ** attempts to lock a CRITICAL_SECTION that is already owned |
| 17 | ** by another thread. The CRITICAL_SECTION object is then |
| 18 | ** released and held by a call to EnterCriticalSection. A new |
| 19 | ** thread is invoked and attempts to acquire the held |
| 20 | ** CRITICAL_SECTION with a call to TryEnterCriticalSection. |
| 21 | ** TryEnterCriticalSection returns immediatly and returns |
| 22 | ** with the value that states the CRITICAL_SECTION object is |
| 23 | ** held by another thread. This establishes |
| 24 | ** TryEnterCriticalSection behaves the same way with |
| 25 | ** CriticalSections locked by TryEnterCriticalSection and |
| 26 | ** EnterCriticalSection. |
| 27 | ** |
| 28 | ** |
| 29 | **===================================================================*/ |
| 30 | #include <palsuite.h> |
| 31 | |
| 32 | #define NUM_THREADS 2 |
| 33 | |
| 34 | HANDLE hThread[NUM_THREADS]; |
| 35 | HANDLE hEvent[NUM_THREADS]; |
| 36 | CRITICAL_SECTION CriticalSection; |
| 37 | BOOL bRet = FAIL; |
| 38 | |
| 39 | DWORD PALAPI Thread(LPVOID lpParam) |
| 40 | { |
| 41 | DWORD dwRet; |
| 42 | |
| 43 | if (0 == TryEnterCriticalSection(&CriticalSection)) |
| 44 | { |
| 45 | dwRet = WaitForMultipleObjects(NUM_THREADS, hEvent, TRUE, 10000); |
| 46 | if ((WAIT_OBJECT_0 > dwRet) || |
| 47 | ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet)) |
| 48 | { |
| 49 | #if 0 |
| 50 | if (0 == CloseHandle(hThread[1])) |
| 51 | { |
| 52 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 53 | "during clean up.\nGetLastError returned '%d'.\n" , |
| 54 | hThread[1], GetLastError()); |
| 55 | } |
| 56 | #endif |
| 57 | Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call" |
| 58 | "returned an unexpected value, '%d'.\nGetLastError returned " |
| 59 | "%d.\n" , NUM_THREADS, hEvent, TRUE, 10000, dwRet, |
| 60 | GetLastError()); |
| 61 | } |
| 62 | else |
| 63 | { |
| 64 | bRet = PASS; |
| 65 | } |
| 66 | } |
| 67 | else |
| 68 | { |
| 69 | /* signal thread 0 */ |
| 70 | if (0 == SetEvent(hEvent[0])) |
| 71 | { |
| 72 | Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during " |
| 73 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 74 | GetLastError()); |
| 75 | LeaveCriticalSection(&CriticalSection); |
| 76 | if (0 == CloseHandle(hThread[0])) |
| 77 | { |
| 78 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 79 | "during clean up\nGetLastError returned '%d'.\n" , |
| 80 | hThread[0], GetLastError()); |
| 81 | } |
| 82 | if (0 == CloseHandle(hEvent[0])) |
| 83 | { |
| 84 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 85 | "during clean up\nGetLastError returned '%d'.\n" , |
| 86 | hEvent[0], GetLastError()); |
| 87 | } |
| 88 | if (0 == CloseHandle(hEvent[1])) |
| 89 | { |
| 90 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 91 | "during clean up\nGetLastError returned '%d'.\n" , |
| 92 | hEvent[1], GetLastError()); |
| 93 | } |
| 94 | DeleteCriticalSection(&CriticalSection); |
| 95 | Fail("" ); |
| 96 | } |
| 97 | |
| 98 | /* wait to be signaled */ |
| 99 | dwRet = WaitForSingleObject(hEvent[1], 10000); |
| 100 | if (WAIT_OBJECT_0 != dwRet) |
| 101 | { |
| 102 | Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have " |
| 103 | "returned\nWAIT_OBJECT_0 ('%d'), instead it returned " |
| 104 | "('%d').\nGetLastError returned '%d'.\n" , |
| 105 | hEvent[0], 10000, WAIT_OBJECT_0, dwRet, GetLastError()); |
| 106 | if (0 == CloseHandle(hThread[0])) |
| 107 | { |
| 108 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 109 | "during clean up.\nGetLastError returned '%d'.\n" , |
| 110 | hThread[0], GetLastError()); |
| 111 | } |
| 112 | if (0 == CloseHandle(hEvent[0])) |
| 113 | { |
| 114 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 115 | "during clean up.\nGetLastError returned '%d'.\n" , |
| 116 | hEvent[0], GetLastError()); |
| 117 | } |
| 118 | if (0 == CloseHandle(hEvent[1])) |
| 119 | { |
| 120 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) " |
| 121 | "during clean up.\nGetLastError returned '%d.'\n" , |
| 122 | hEvent[1], GetLastError()); |
| 123 | } |
| 124 | DeleteCriticalSection(&CriticalSection); |
| 125 | Fail("" ); |
| 126 | } |
| 127 | LeaveCriticalSection(&CriticalSection); |
| 128 | } |
| 129 | return FAIL; |
| 130 | } |
| 131 | |
| 132 | int __cdecl main(int argc, char **argv) |
| 133 | { |
| 134 | HANDLE hThread[NUM_THREADS]; |
| 135 | DWORD dwThreadId[NUM_THREADS]; |
| 136 | DWORD dwRet; |
| 137 | |
| 138 | if ((PAL_Initialize(argc,argv)) != 0) |
| 139 | { |
| 140 | return(bRet); |
| 141 | } |
| 142 | |
| 143 | /* thread 0 event */ |
| 144 | hEvent[0] = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 145 | |
| 146 | if (hEvent[0] == NULL) |
| 147 | { |
| 148 | Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError " |
| 149 | "returned %d.\n" , GetLastError()); |
| 150 | } |
| 151 | |
| 152 | /* thread 1 event */ |
| 153 | hEvent[1] = CreateEvent(NULL, TRUE, FALSE, NULL); |
| 154 | |
| 155 | if (hEvent[1] == NULL) |
| 156 | { |
| 157 | Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError " |
| 158 | "returned %d.\n" , GetLastError()); |
| 159 | if (0 == CloseHandle(hEvent[0])) |
| 160 | { |
| 161 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 162 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0]); |
| 163 | } |
| 164 | Fail("" ); |
| 165 | } |
| 166 | |
| 167 | InitializeCriticalSection ( &CriticalSection ); |
| 168 | |
| 169 | hThread[0] = CreateThread(NULL, |
| 170 | 0, |
| 171 | &Thread, |
| 172 | (LPVOID) NULL, |
| 173 | 0, |
| 174 | &dwThreadId[0]); |
| 175 | |
| 176 | if (hThread[0] == NULL) |
| 177 | { |
| 178 | Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError " |
| 179 | "returned %d.\n" , GetLastError()); |
| 180 | if (0 == CloseHandle(hEvent[0])) |
| 181 | { |
| 182 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 183 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 184 | GetLastError()); |
| 185 | } |
| 186 | if (0 == CloseHandle(hEvent[1])) |
| 187 | { |
| 188 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 189 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 190 | GetLastError()); |
| 191 | } |
| 192 | DeleteCriticalSection(&CriticalSection); |
| 193 | Fail("" ); |
| 194 | } |
| 195 | |
| 196 | |
| 197 | /* wait for thread 0 to be signaled */ |
| 198 | dwRet = WaitForSingleObject(hEvent[0], 10000); |
| 199 | if (WAIT_OBJECT_0 != dwRet) |
| 200 | { |
| 201 | Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have " |
| 202 | "returned\nWAIT_OBJECT_0 ('%d'), instead it returned " |
| 203 | "('%d').\nGetLastError returned '%d'.\n" , hEvent[0], 10000, |
| 204 | WAIT_OBJECT_0, dwRet, GetLastError()); |
| 205 | if (0 == CloseHandle(hThread[0])) |
| 206 | { |
| 207 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 208 | "clean up.\nGetLastError returned '%d'.\n" , hThread[0], |
| 209 | GetLastError()); |
| 210 | } |
| 211 | if (0 == CloseHandle(hEvent[0])) |
| 212 | { |
| 213 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 214 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 215 | GetLastError()); |
| 216 | } |
| 217 | if (0 == CloseHandle(hEvent[1])) |
| 218 | { |
| 219 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 220 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 221 | GetLastError()); |
| 222 | } |
| 223 | Fail("" ); |
| 224 | } |
| 225 | |
| 226 | /* |
| 227 | * Attempting to enter CRITICAL_SECTION object owned by the |
| 228 | * created thread and locked with TryEnterCriticalSection |
| 229 | */ |
| 230 | if (0 == TryEnterCriticalSection(&CriticalSection)) |
| 231 | { |
| 232 | /* signal thread 1 */ |
| 233 | if (0 == SetEvent(hEvent[1])) |
| 234 | { |
| 235 | Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n" |
| 236 | "GetLastError returned '%d'.\n" , hEvent[1], |
| 237 | GetLastError()); |
| 238 | goto done; |
| 239 | } |
| 240 | } |
| 241 | else |
| 242 | { |
| 243 | Trace("PALSUITE_ERROR: TryEnterCriticalSection was able to grab a" |
| 244 | " CRITICAL_SECTION object\nwhich was already owned.\n" ); |
| 245 | LeaveCriticalSection(&CriticalSection); |
| 246 | if (0 == CloseHandle(hThread[0])) |
| 247 | { |
| 248 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 249 | "clean up.\nGetLastError returned '%d'.\n" , hThread[0], |
| 250 | GetLastError()); |
| 251 | } |
| 252 | if (0 == CloseHandle(hEvent[0])) |
| 253 | { |
| 254 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 255 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 256 | GetLastError()); |
| 257 | } |
| 258 | if (0 == CloseHandle(hEvent[1])) |
| 259 | { |
| 260 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 261 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 262 | GetLastError()); |
| 263 | } |
| 264 | DeleteCriticalSection(&CriticalSection); |
| 265 | Fail("" ); |
| 266 | } |
| 267 | /* |
| 268 | * Enter the CRITICAL_SECTION and launch another thread to attempt |
| 269 | * to access the CRITICAL_SECTION with a call to TryEnterCriticalSection. |
| 270 | */ |
| 271 | EnterCriticalSection(&CriticalSection); |
| 272 | |
| 273 | hThread[1] = CreateThread(NULL, |
| 274 | 0, |
| 275 | &Thread, |
| 276 | (LPVOID) NULL, |
| 277 | 0, |
| 278 | &dwThreadId[1]); |
| 279 | |
| 280 | if (hThread[1] == NULL) |
| 281 | { |
| 282 | Trace("PALSUITE ERROR: CreateThread call #1 failed. GetLastError " |
| 283 | "returned %d.\n" , GetLastError()); |
| 284 | LeaveCriticalSection(&CriticalSection); |
| 285 | if (0 == CloseHandle(hThread[0])) |
| 286 | { |
| 287 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 288 | "clean up.\nGetLastError returned '%d'.\n" , hThread[0], |
| 289 | GetLastError()); |
| 290 | } |
| 291 | if (0 == CloseHandle(hEvent[0])) |
| 292 | { |
| 293 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 294 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 295 | GetLastError()); |
| 296 | } |
| 297 | if (0 == CloseHandle(hEvent[1])) |
| 298 | { |
| 299 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 300 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 301 | GetLastError()); |
| 302 | } |
| 303 | DeleteCriticalSection(&CriticalSection); |
| 304 | Fail("" ); |
| 305 | } |
| 306 | |
| 307 | dwRet = WaitForMultipleObjects(NUM_THREADS, hThread, TRUE, 10000); |
| 308 | if ((WAIT_OBJECT_0 > dwRet) || |
| 309 | ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet)) |
| 310 | { |
| 311 | Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call " |
| 312 | "returned an unexpected value, '%d'.\nGetLastError returned " |
| 313 | "%d.\n" , NUM_THREADS, hThread, TRUE, 10000, dwRet, |
| 314 | GetLastError()); |
| 315 | LeaveCriticalSection(&CriticalSection); |
| 316 | if (0 == CloseHandle(hThread[0])) |
| 317 | { |
| 318 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 319 | "clean up.\nGetLastError returned '%d'.\n" , hThread[0], |
| 320 | GetLastError()); |
| 321 | } |
| 322 | if (0 == CloseHandle(hThread[1])) |
| 323 | { |
| 324 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 325 | "clean up.\nGetLastError returned '%d'.\n" , hThread[1], |
| 326 | GetLastError()); |
| 327 | } |
| 328 | if (0 == CloseHandle(hEvent[0])) |
| 329 | { |
| 330 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 331 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 332 | GetLastError()); |
| 333 | } |
| 334 | if (0 == CloseHandle(hEvent[1])) |
| 335 | { |
| 336 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 337 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 338 | GetLastError()); |
| 339 | } |
| 340 | DeleteCriticalSection(&CriticalSection); |
| 341 | Fail("" ); |
| 342 | } |
| 343 | |
| 344 | LeaveCriticalSection(&CriticalSection); |
| 345 | if (0 == CloseHandle(hThread[1])) |
| 346 | { |
| 347 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 348 | "clean up.\nGetLastError returned '%d'.\n" , hThread[1], |
| 349 | GetLastError()); |
| 350 | } |
| 351 | done: |
| 352 | if (0 == CloseHandle(hThread[0])) |
| 353 | { |
| 354 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 355 | "clean up.\nGetLastError returned '%d'.\n" , hThread[0], |
| 356 | GetLastError()); |
| 357 | } |
| 358 | if (0 == CloseHandle(hEvent[0])) |
| 359 | { |
| 360 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 361 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[0], |
| 362 | GetLastError()); |
| 363 | } |
| 364 | if (0 == CloseHandle(hEvent[1])) |
| 365 | { |
| 366 | Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during " |
| 367 | "clean up.\nGetLastError returned '%d'.\n" , hEvent[1], |
| 368 | GetLastError()); |
| 369 | } |
| 370 | DeleteCriticalSection(&CriticalSection); |
| 371 | |
| 372 | PAL_TerminateEx(bRet); |
| 373 | |
| 374 | return (bRet); |
| 375 | } |
| 376 | |
| 377 | |