| 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 | |
| 8 | |
| 9 | Module Name: |
| 10 | |
| 11 | semaphore.cpp |
| 12 | |
| 13 | Abstract: |
| 14 | |
| 15 | Implementation of the sempahore synchroniztion object as described in |
| 16 | the WIN32 API |
| 17 | |
| 18 | Revision History: |
| 19 | |
| 20 | |
| 21 | |
| 22 | --*/ |
| 23 | |
| 24 | #include "pal/semaphore.hpp" |
| 25 | #include "pal/thread.hpp" |
| 26 | #include "pal/dbgmsg.h" |
| 27 | |
| 28 | using namespace CorUnix; |
| 29 | |
| 30 | /* ------------------- Definitions ------------------------------*/ |
| 31 | SET_DEFAULT_DEBUG_CHANNEL(SYNC); |
| 32 | |
| 33 | CObjectType CorUnix::otSemaphore( |
| 34 | otiSemaphore, |
| 35 | NULL, // No cleanup routine |
| 36 | NULL, // No initialization routine |
| 37 | sizeof(SemaphoreImmutableData), |
| 38 | NULL, // No immutable data copy routine |
| 39 | NULL, // No immutable data cleanup routine |
| 40 | 0, // No process local data |
| 41 | NULL, // No process local data cleanup routine |
| 42 | 0, // No shared data |
| 43 | 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security) |
| 44 | CObjectType::SecuritySupported, |
| 45 | CObjectType::SecurityInfoNotPersisted, |
| 46 | CObjectType::UnnamedObject, |
| 47 | CObjectType::LocalDuplicationOnly, |
| 48 | CObjectType::WaitableObject, |
| 49 | CObjectType::ObjectCanBeUnsignaled, |
| 50 | CObjectType::ThreadReleaseAltersSignalCount, |
| 51 | CObjectType::NoOwner |
| 52 | ); |
| 53 | |
| 54 | CAllowedObjectTypes aotSempahore(otiSemaphore); |
| 55 | |
| 56 | /*++ |
| 57 | Function: |
| 58 | CreateSemaphoreExA |
| 59 | |
| 60 | Note: |
| 61 | lpSemaphoreAttributes currently ignored: |
| 62 | -- Win32 object security not supported |
| 63 | -- handles to semaphore objects are not inheritable |
| 64 | |
| 65 | Parameters: |
| 66 | See MSDN doc. |
| 67 | --*/ |
| 68 | |
| 69 | HANDLE |
| 70 | PALAPI |
| 71 | CreateSemaphoreExA( |
| 72 | IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, |
| 73 | IN LONG lInitialCount, |
| 74 | IN LONG lMaximumCount, |
| 75 | IN LPCSTR lpName, |
| 76 | IN /*_Reserved_*/ DWORD dwFlags, |
| 77 | IN DWORD dwDesiredAccess) |
| 78 | { |
| 79 | // dwFlags is reserved and unused, and dwDesiredAccess is currently |
| 80 | // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters |
| 81 | // all map to CreateSemaphoreA. |
| 82 | _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess); |
| 83 | |
| 84 | return CreateSemaphoreA( |
| 85 | lpSemaphoreAttributes, |
| 86 | lInitialCount, |
| 87 | lMaximumCount, |
| 88 | lpName); |
| 89 | } |
| 90 | |
| 91 | /*++ |
| 92 | Function: |
| 93 | CreateSemaphoreA |
| 94 | |
| 95 | Note: |
| 96 | lpSemaphoreAttributes currently ignored: |
| 97 | -- Win32 object security not supported |
| 98 | -- handles to semaphore objects are not inheritable |
| 99 | |
| 100 | Parameters: |
| 101 | See MSDN doc. |
| 102 | --*/ |
| 103 | |
| 104 | HANDLE |
| 105 | PALAPI |
| 106 | CreateSemaphoreA( |
| 107 | IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, |
| 108 | IN LONG lInitialCount, |
| 109 | IN LONG lMaximumCount, |
| 110 | IN LPCSTR lpName) |
| 111 | { |
| 112 | HANDLE hSemaphore = NULL; |
| 113 | CPalThread *pthr = NULL; |
| 114 | PAL_ERROR palError; |
| 115 | |
| 116 | PERF_ENTRY(CreateSemaphoreA); |
| 117 | ENTRY("CreateSemaphoreA(lpSemaphoreAttributes=%p, lInitialCount=%d, " |
| 118 | "lMaximumCount=%d, lpName=%p (%s))\n" , |
| 119 | lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, lpName?lpName:"NULL" ); |
| 120 | |
| 121 | pthr = InternalGetCurrentThread(); |
| 122 | |
| 123 | if (lpName != nullptr) |
| 124 | { |
| 125 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
| 126 | palError = ERROR_NOT_SUPPORTED; |
| 127 | } |
| 128 | else |
| 129 | { |
| 130 | palError = InternalCreateSemaphore( |
| 131 | pthr, |
| 132 | lpSemaphoreAttributes, |
| 133 | lInitialCount, |
| 134 | lMaximumCount, |
| 135 | NULL, |
| 136 | &hSemaphore |
| 137 | ); |
| 138 | } |
| 139 | |
| 140 | // |
| 141 | // We always need to set last error, even on success: |
| 142 | // we need to protect ourselves from the situation |
| 143 | // where last error is set to ERROR_ALREADY_EXISTS on |
| 144 | // entry to the function |
| 145 | // |
| 146 | |
| 147 | pthr->SetLastError(palError); |
| 148 | |
| 149 | LOGEXIT("CreateSemaphoreA returns HANDLE %p\n" , hSemaphore); |
| 150 | PERF_EXIT(CreateSemaphoreA); |
| 151 | return hSemaphore; |
| 152 | } |
| 153 | |
| 154 | /*++ |
| 155 | Function: |
| 156 | CreateSemaphoreExW |
| 157 | |
| 158 | Note: |
| 159 | lpSemaphoreAttributes currentely ignored: |
| 160 | -- Win32 object security not supported |
| 161 | -- handles to semaphore objects are not inheritable |
| 162 | |
| 163 | Parameters: |
| 164 | See MSDN doc. |
| 165 | --*/ |
| 166 | |
| 167 | HANDLE |
| 168 | PALAPI |
| 169 | CreateSemaphoreExW( |
| 170 | IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, |
| 171 | IN LONG lInitialCount, |
| 172 | IN LONG lMaximumCount, |
| 173 | IN LPCWSTR lpName, |
| 174 | IN /*_Reserved_*/ DWORD dwFlags, |
| 175 | IN DWORD dwDesiredAccess) |
| 176 | { |
| 177 | // dwFlags is reserved and unused |
| 178 | |
| 179 | return CreateSemaphoreW( |
| 180 | lpSemaphoreAttributes, |
| 181 | lInitialCount, |
| 182 | lMaximumCount, |
| 183 | lpName); |
| 184 | } |
| 185 | |
| 186 | /*++ |
| 187 | Function: |
| 188 | CreateSemaphoreW |
| 189 | |
| 190 | Note: |
| 191 | lpSemaphoreAttributes currentely ignored: |
| 192 | -- Win32 object security not supported |
| 193 | -- handles to semaphore objects are not inheritable |
| 194 | |
| 195 | Parameters: |
| 196 | See MSDN doc. |
| 197 | --*/ |
| 198 | |
| 199 | HANDLE |
| 200 | PALAPI |
| 201 | CreateSemaphoreW( |
| 202 | IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, |
| 203 | IN LONG lInitialCount, |
| 204 | IN LONG lMaximumCount, |
| 205 | IN LPCWSTR lpName) |
| 206 | { |
| 207 | HANDLE hSemaphore = NULL; |
| 208 | PAL_ERROR palError; |
| 209 | CPalThread *pthr = NULL; |
| 210 | |
| 211 | PERF_ENTRY(CreateSemaphoreW); |
| 212 | ENTRY("CreateSemaphoreW(lpSemaphoreAttributes=%p, lInitialCount=%d, " |
| 213 | "lMaximumCount=%d, lpName=%p (%S))\n" , |
| 214 | lpSemaphoreAttributes, lInitialCount, lMaximumCount, |
| 215 | lpName, lpName?lpName:W16_NULLSTRING); |
| 216 | |
| 217 | pthr = InternalGetCurrentThread(); |
| 218 | |
| 219 | palError = InternalCreateSemaphore( |
| 220 | pthr, |
| 221 | lpSemaphoreAttributes, |
| 222 | lInitialCount, |
| 223 | lMaximumCount, |
| 224 | lpName, |
| 225 | &hSemaphore |
| 226 | ); |
| 227 | |
| 228 | // |
| 229 | // We always need to set last error, even on success: |
| 230 | // we need to protect ourselves from the situation |
| 231 | // where last error is set to ERROR_ALREADY_EXISTS on |
| 232 | // entry to the function |
| 233 | // |
| 234 | |
| 235 | pthr->SetLastError(palError); |
| 236 | |
| 237 | LOGEXIT("CreateSemaphoreW returns HANDLE %p\n" , hSemaphore); |
| 238 | PERF_EXIT(CreateSemaphoreW); |
| 239 | return hSemaphore; |
| 240 | } |
| 241 | |
| 242 | /*++ |
| 243 | Function: |
| 244 | InternalCreateSemaphore |
| 245 | |
| 246 | Note: |
| 247 | lpSemaphoreAttributes currentely ignored: |
| 248 | -- Win32 object security not supported |
| 249 | -- handles to semaphore objects are not inheritable |
| 250 | |
| 251 | Parameters |
| 252 | pthr -- thread data for calling thread |
| 253 | phEvent -- on success, receives the allocated semaphore handle |
| 254 | |
| 255 | See MSDN docs on CreateSemaphore for all other parameters. |
| 256 | --*/ |
| 257 | |
| 258 | PAL_ERROR |
| 259 | CorUnix::InternalCreateSemaphore( |
| 260 | CPalThread *pthr, |
| 261 | LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, |
| 262 | LONG lInitialCount, |
| 263 | LONG lMaximumCount, |
| 264 | LPCWSTR lpName, |
| 265 | HANDLE *phSemaphore |
| 266 | ) |
| 267 | { |
| 268 | CObjectAttributes oa(lpName, lpSemaphoreAttributes); |
| 269 | PAL_ERROR palError = NO_ERROR; |
| 270 | IPalObject *pobjSemaphore = NULL; |
| 271 | IPalObject *pobjRegisteredSemaphore = NULL; |
| 272 | SemaphoreImmutableData *pSemaphoreData; |
| 273 | |
| 274 | _ASSERTE(NULL != pthr); |
| 275 | _ASSERTE(NULL != phSemaphore); |
| 276 | |
| 277 | ENTRY("InternalCreateSemaphore(pthr=%p, lpSemaphoreAttributes=%p, " |
| 278 | "lInitialCount=%d, lMaximumCount=%d, lpName=%p, phSemaphore=%p)\n" , |
| 279 | pthr, |
| 280 | lpSemaphoreAttributes, |
| 281 | lInitialCount, |
| 282 | lMaximumCount, |
| 283 | lpName, |
| 284 | phSemaphore |
| 285 | ); |
| 286 | |
| 287 | if (lpName != nullptr) |
| 288 | { |
| 289 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
| 290 | palError = ERROR_NOT_SUPPORTED; |
| 291 | goto InternalCreateSemaphoreExit; |
| 292 | } |
| 293 | |
| 294 | if (lMaximumCount <= 0) |
| 295 | { |
| 296 | ERROR("lMaximumCount is invalid (%d)\n" , lMaximumCount); |
| 297 | palError = ERROR_INVALID_PARAMETER; |
| 298 | goto InternalCreateSemaphoreExit; |
| 299 | } |
| 300 | |
| 301 | if ((lInitialCount < 0) || (lInitialCount > lMaximumCount)) |
| 302 | { |
| 303 | ERROR("lInitialCount is invalid (%d)\n" , lInitialCount); |
| 304 | palError = ERROR_INVALID_PARAMETER; |
| 305 | goto InternalCreateSemaphoreExit; |
| 306 | } |
| 307 | |
| 308 | palError = g_pObjectManager->AllocateObject( |
| 309 | pthr, |
| 310 | &otSemaphore, |
| 311 | &oa, |
| 312 | &pobjSemaphore |
| 313 | ); |
| 314 | |
| 315 | if (NO_ERROR != palError) |
| 316 | { |
| 317 | goto InternalCreateSemaphoreExit; |
| 318 | } |
| 319 | |
| 320 | palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData)); |
| 321 | |
| 322 | if (NO_ERROR != palError) |
| 323 | { |
| 324 | ASSERT("Error %d obtaining object data\n" , palError); |
| 325 | goto InternalCreateSemaphoreExit; |
| 326 | } |
| 327 | |
| 328 | pSemaphoreData->lMaximumCount = lMaximumCount; |
| 329 | |
| 330 | if (0 != lInitialCount) |
| 331 | { |
| 332 | ISynchStateController *pssc; |
| 333 | |
| 334 | palError = pobjSemaphore->GetSynchStateController( |
| 335 | pthr, |
| 336 | &pssc |
| 337 | ); |
| 338 | |
| 339 | if (NO_ERROR == palError) |
| 340 | { |
| 341 | palError = pssc->SetSignalCount(lInitialCount); |
| 342 | pssc->ReleaseController(); |
| 343 | } |
| 344 | |
| 345 | if (NO_ERROR != palError) |
| 346 | { |
| 347 | ASSERT("Unable to set new semaphore state (%d)\n" , palError); |
| 348 | goto InternalCreateSemaphoreExit; |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | palError = g_pObjectManager->RegisterObject( |
| 353 | pthr, |
| 354 | pobjSemaphore, |
| 355 | &aotSempahore, |
| 356 | 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security) |
| 357 | phSemaphore, |
| 358 | &pobjRegisteredSemaphore |
| 359 | ); |
| 360 | |
| 361 | // |
| 362 | // pobjSemaphore is invalidated by the call to RegisterObject, so NULL it |
| 363 | // out here to ensure that we don't try to release a reference on |
| 364 | // it down the line. |
| 365 | // |
| 366 | |
| 367 | pobjSemaphore = NULL; |
| 368 | |
| 369 | InternalCreateSemaphoreExit: |
| 370 | |
| 371 | if (NULL != pobjSemaphore) |
| 372 | { |
| 373 | pobjSemaphore->ReleaseReference(pthr); |
| 374 | } |
| 375 | |
| 376 | if (NULL != pobjRegisteredSemaphore) |
| 377 | { |
| 378 | pobjRegisteredSemaphore->ReleaseReference(pthr); |
| 379 | } |
| 380 | |
| 381 | LOGEXIT("InternalCreateSemaphore returns %d\n" , palError); |
| 382 | |
| 383 | return palError; |
| 384 | } |
| 385 | |
| 386 | |
| 387 | /*++ |
| 388 | Function: |
| 389 | ReleaseSemaphore |
| 390 | |
| 391 | Parameters: |
| 392 | See MSDN doc. |
| 393 | --*/ |
| 394 | |
| 395 | BOOL |
| 396 | PALAPI |
| 397 | ReleaseSemaphore( |
| 398 | IN HANDLE hSemaphore, |
| 399 | IN LONG lReleaseCount, |
| 400 | OUT LPLONG lpPreviousCount) |
| 401 | { |
| 402 | PAL_ERROR palError = NO_ERROR; |
| 403 | CPalThread *pthr = NULL; |
| 404 | |
| 405 | PERF_ENTRY(ReleaseSemaphore); |
| 406 | ENTRY("ReleaseSemaphore(hSemaphore=%p, lReleaseCount=%d, " |
| 407 | "lpPreviousCount=%p)\n" , |
| 408 | hSemaphore, lReleaseCount, lpPreviousCount); |
| 409 | |
| 410 | pthr = InternalGetCurrentThread(); |
| 411 | |
| 412 | palError = InternalReleaseSemaphore( |
| 413 | pthr, |
| 414 | hSemaphore, |
| 415 | lReleaseCount, |
| 416 | lpPreviousCount |
| 417 | ); |
| 418 | |
| 419 | if (NO_ERROR != palError) |
| 420 | { |
| 421 | pthr->SetLastError(palError); |
| 422 | } |
| 423 | |
| 424 | LOGEXIT ("ReleaseSemaphore returns BOOL %d\n" , (NO_ERROR == palError)); |
| 425 | PERF_EXIT(ReleaseSemaphore); |
| 426 | return (NO_ERROR == palError); |
| 427 | } |
| 428 | |
| 429 | /*++ |
| 430 | Function: |
| 431 | InternalReleaseSemaphore |
| 432 | |
| 433 | Parameters: |
| 434 | pthr -- thread data for calling thread |
| 435 | |
| 436 | See MSDN docs on ReleaseSemaphore for all other parameters |
| 437 | --*/ |
| 438 | |
| 439 | PAL_ERROR |
| 440 | CorUnix::InternalReleaseSemaphore( |
| 441 | CPalThread *pthr, |
| 442 | HANDLE hSemaphore, |
| 443 | LONG lReleaseCount, |
| 444 | LPLONG lpPreviousCount |
| 445 | ) |
| 446 | { |
| 447 | PAL_ERROR palError = NO_ERROR; |
| 448 | IPalObject *pobjSemaphore = NULL; |
| 449 | ISynchStateController *pssc = NULL; |
| 450 | SemaphoreImmutableData *pSemaphoreData; |
| 451 | LONG lOldCount; |
| 452 | |
| 453 | _ASSERTE(NULL != pthr); |
| 454 | |
| 455 | ENTRY("InternalReleaseSempahore(pthr=%p, hSemaphore=%p, lReleaseCount=%d, " |
| 456 | "lpPreviousCount=%p)\n" , |
| 457 | pthr, |
| 458 | hSemaphore, |
| 459 | lReleaseCount, |
| 460 | lpPreviousCount |
| 461 | ); |
| 462 | |
| 463 | if (0 >= lReleaseCount) |
| 464 | { |
| 465 | palError = ERROR_INVALID_PARAMETER; |
| 466 | goto InternalReleaseSemaphoreExit; |
| 467 | } |
| 468 | |
| 469 | palError = g_pObjectManager->ReferenceObjectByHandle( |
| 470 | pthr, |
| 471 | hSemaphore, |
| 472 | &aotSempahore, |
| 473 | 0, // Should be SEMAPHORE_MODIFY_STATE; currently ignored (no Win32 security) |
| 474 | &pobjSemaphore |
| 475 | ); |
| 476 | |
| 477 | if (NO_ERROR != palError) |
| 478 | { |
| 479 | ERROR("Unable to obtain object for handle %p (error %d)!\n" , hSemaphore, palError); |
| 480 | goto InternalReleaseSemaphoreExit; |
| 481 | } |
| 482 | |
| 483 | palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData)); |
| 484 | |
| 485 | if (NO_ERROR != palError) |
| 486 | { |
| 487 | ASSERT("Error %d obtaining object data\n" , palError); |
| 488 | goto InternalReleaseSemaphoreExit; |
| 489 | } |
| 490 | |
| 491 | palError = pobjSemaphore->GetSynchStateController( |
| 492 | pthr, |
| 493 | &pssc |
| 494 | ); |
| 495 | |
| 496 | if (NO_ERROR != palError) |
| 497 | { |
| 498 | ASSERT("Error %d obtaining synch state controller\n" , palError); |
| 499 | goto InternalReleaseSemaphoreExit; |
| 500 | } |
| 501 | |
| 502 | palError = pssc->GetSignalCount(&lOldCount); |
| 503 | |
| 504 | if (NO_ERROR != palError) |
| 505 | { |
| 506 | ASSERT("Error %d obtaining current signal count\n" , palError); |
| 507 | goto InternalReleaseSemaphoreExit; |
| 508 | } |
| 509 | |
| 510 | _ASSERTE(lOldCount <= pSemaphoreData->lMaximumCount); |
| 511 | if (lReleaseCount > pSemaphoreData->lMaximumCount - lOldCount) |
| 512 | { |
| 513 | palError = ERROR_TOO_MANY_POSTS; |
| 514 | goto InternalReleaseSemaphoreExit; |
| 515 | } |
| 516 | |
| 517 | palError = pssc->IncrementSignalCount(lReleaseCount); |
| 518 | |
| 519 | if (NO_ERROR != palError) |
| 520 | { |
| 521 | ASSERT("Error %d incrementing signal count\n" , palError); |
| 522 | goto InternalReleaseSemaphoreExit; |
| 523 | } |
| 524 | |
| 525 | if (NULL != lpPreviousCount) |
| 526 | { |
| 527 | *lpPreviousCount = lOldCount; |
| 528 | } |
| 529 | |
| 530 | InternalReleaseSemaphoreExit: |
| 531 | |
| 532 | if (NULL != pssc) |
| 533 | { |
| 534 | pssc->ReleaseController(); |
| 535 | } |
| 536 | |
| 537 | if (NULL != pobjSemaphore) |
| 538 | { |
| 539 | pobjSemaphore->ReleaseReference(pthr); |
| 540 | } |
| 541 | |
| 542 | LOGEXIT("InternalReleaseSemaphore returns %d\n" , palError); |
| 543 | |
| 544 | return palError; |
| 545 | } |
| 546 | |
| 547 | // TODO: Implementation of OpenSemaphoreA() doesn't exist, do we need it? More generally, do we need the A versions at all? |
| 548 | |
| 549 | /*++ |
| 550 | Function: |
| 551 | OpenSemaphoreW |
| 552 | |
| 553 | Note: |
| 554 | dwDesiredAccess is currently ignored (no Win32 object security support) |
| 555 | bInheritHandle is currently ignored (handles to semaphore are not inheritable) |
| 556 | |
| 557 | Parameters: |
| 558 | See MSDN doc. |
| 559 | --*/ |
| 560 | |
| 561 | HANDLE |
| 562 | PALAPI |
| 563 | OpenSemaphoreW( |
| 564 | IN DWORD dwDesiredAccess, |
| 565 | IN BOOL bInheritHandle, |
| 566 | IN LPCWSTR lpName) |
| 567 | { |
| 568 | HANDLE hSemaphore = NULL; |
| 569 | PAL_ERROR palError = NO_ERROR; |
| 570 | CPalThread *pthr = NULL; |
| 571 | |
| 572 | PERF_ENTRY(OpenSemaphoreW); |
| 573 | ENTRY("OpenSemaphoreW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n" , |
| 574 | dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING); |
| 575 | |
| 576 | pthr = InternalGetCurrentThread(); |
| 577 | |
| 578 | /* validate parameters */ |
| 579 | if (lpName == nullptr) |
| 580 | { |
| 581 | ERROR("lpName is NULL\n" ); |
| 582 | palError = ERROR_INVALID_PARAMETER; |
| 583 | } |
| 584 | else |
| 585 | { |
| 586 | ASSERT("lpName: Cross-process named objects are not supported in PAL" ); |
| 587 | palError = ERROR_NOT_SUPPORTED; |
| 588 | } |
| 589 | |
| 590 | if (NO_ERROR != palError) |
| 591 | { |
| 592 | pthr->SetLastError(palError); |
| 593 | } |
| 594 | |
| 595 | LOGEXIT("OpenSemaphoreW returns HANDLE %p\n" , hSemaphore); |
| 596 | PERF_EXIT(OpenSemaphoreW); |
| 597 | |
| 598 | return hSemaphore; |
| 599 | } |
| 600 | |