summaryrefslogtreecommitdiff
path: root/src/pal/src/synchobj/semaphore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/synchobj/semaphore.cpp')
-rw-r--r--src/pal/src/synchobj/semaphore.cpp680
1 files changed, 680 insertions, 0 deletions
diff --git a/src/pal/src/synchobj/semaphore.cpp b/src/pal/src/synchobj/semaphore.cpp
new file mode 100644
index 0000000000..b2240184c5
--- /dev/null
+++ b/src/pal/src/synchobj/semaphore.cpp
@@ -0,0 +1,680 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ semaphore.cpp
+
+Abstract:
+
+ Implementation of the sempahore synchroniztion object as described in
+ the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/semaphore.hpp"
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+SET_DEFAULT_DEBUG_CHANNEL(SYNC);
+
+CObjectType CorUnix::otSemaphore(
+ otiSemaphore,
+ NULL, // No cleanup routine
+ NULL, // No initialization routine
+ sizeof(SemaphoreImmutableData),
+ 0, // No process local data
+ 0, // No shared data
+ 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::ObjectCanBeUnsignaled,
+ CObjectType::ThreadReleaseAltersSignalCount,
+ CObjectType::NoOwner
+ );
+
+CAllowedObjectTypes aotSempahore(otiSemaphore);
+
+/*++
+Function:
+CreateSemaphoreExA
+
+Note:
+lpSemaphoreAttributes currently ignored:
+-- Win32 object security not supported
+-- handles to semaphore objects are not inheritable
+
+Parameters:
+See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreExA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess)
+{
+ // dwFlags is reserved and unused, and dwDesiredAccess is currently
+ // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters
+ // all map to CreateSemaphoreA.
+ _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess);
+
+ return CreateSemaphoreA(
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName);
+}
+
+/*++
+Function:
+ CreateSemaphoreA
+
+Note:
+ lpSemaphoreAttributes currently ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ CPalThread *pthr = NULL;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(CreateSemaphoreA);
+ ENTRY("CreateSemaphoreA(lpSemaphoreAttributes=%p, lInitialCount=%d, "
+ "lMaximumCount=%d, lpName=%p (%s))\n",
+ lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, lpName?lpName:"NULL");
+
+ pthr = InternalGetCurrentThread();
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ palError = InternalCreateSemaphore(
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ NULL,
+ &hSemaphore
+ );
+ }
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateSemaphoreA returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(CreateSemaphoreA);
+ return hSemaphore;
+}
+
+/*++
+Function:
+CreateSemaphoreExW
+
+Note:
+lpSemaphoreAttributes currentely ignored:
+-- Win32 object security not supported
+-- handles to semaphore objects are not inheritable
+
+Parameters:
+See MSDN doc.
+--*/
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreExW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess)
+{
+ // dwFlags is reserved and unused, and dwDesiredAccess is currently
+ // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters
+ // all map to CreateSemaphoreW.
+ _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess);
+
+ return CreateSemaphoreW(
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName);
+}
+
+/*++
+Function:
+ CreateSemaphoreW
+
+Note:
+ lpSemaphoreAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ PAL_ERROR palError;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(CreateSemaphoreW);
+ ENTRY("CreateSemaphoreW(lpSemaphoreAttributes=%p, lInitialCount=%d, "
+ "lMaximumCount=%d, lpName=%p (%S))\n",
+ lpSemaphoreAttributes, lInitialCount, lMaximumCount,
+ lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalCreateSemaphore(
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName,
+ &hSemaphore
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateSemaphoreW returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(CreateSemaphoreW);
+ return hSemaphore;
+}
+
+/*++
+Function:
+ InternalCreateSemaphore
+
+Note:
+ lpSemaphoreAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated semaphore handle
+
+ See MSDN docs on CreateSemaphore for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalCreateSemaphore(
+ CPalThread *pthr,
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ LONG lInitialCount,
+ LONG lMaximumCount,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ )
+{
+ CObjectAttributes oa(lpName, lpSemaphoreAttributes);
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ IPalObject *pobjRegisteredSemaphore = NULL;
+ SemaphoreImmutableData *pSemaphoreData;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != phSemaphore);
+
+ ENTRY("InternalCreateSemaphore(pthr=%p, lpSemaphoreAttributes=%p, "
+ "lInitialCount=%d, lMaximumCount=%d, lpName=%p, phSemaphore=%p)\n",
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName,
+ phSemaphore
+ );
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ if (lMaximumCount <= 0)
+ {
+ ERROR("lMaximumCount is invalid (%d)\n", lMaximumCount);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ if ((lInitialCount < 0) || (lInitialCount > lMaximumCount))
+ {
+ ERROR("lInitialCount is invalid (%d)\n", lInitialCount);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pthr,
+ &otSemaphore,
+ &oa,
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining object data\n", palError);
+ goto InternalCreateSemaphoreExit;
+ }
+
+ pSemaphoreData->lMaximumCount = lMaximumCount;
+
+ if (0 != lInitialCount)
+ {
+ ISynchStateController *pssc;
+
+ palError = pobjSemaphore->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pssc->SetSignalCount(lInitialCount);
+ pssc->ReleaseController();
+ }
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to set new semaphore state (%d)\n", palError);
+ goto InternalCreateSemaphoreExit;
+ }
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pthr,
+ pobjSemaphore,
+ &aotSempahore,
+ 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
+ phSemaphore,
+ &pobjRegisteredSemaphore
+ );
+
+ //
+ // pobjSemaphore is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pobjSemaphore = NULL;
+
+InternalCreateSemaphoreExit:
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ if (NULL != pobjRegisteredSemaphore)
+ {
+ pobjRegisteredSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalCreateSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+
+/*++
+Function:
+ ReleaseSemaphore
+
+Parameters:
+ See MSDN doc.
+--*/
+
+BOOL
+PALAPI
+ReleaseSemaphore(
+ IN HANDLE hSemaphore,
+ IN LONG lReleaseCount,
+ OUT LPLONG lpPreviousCount)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(ReleaseSemaphore);
+ ENTRY("ReleaseSemaphore(hSemaphore=%p, lReleaseCount=%d, "
+ "lpPreviousCount=%p)\n",
+ hSemaphore, lReleaseCount, lpPreviousCount);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalReleaseSemaphore(
+ pthr,
+ hSemaphore,
+ lReleaseCount,
+ lpPreviousCount
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT ("ReleaseSemaphore returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(ReleaseSemaphore);
+ return (NO_ERROR == palError);
+}
+
+/*++
+Function:
+ InternalReleaseSemaphore
+
+Parameters:
+ pthr -- thread data for calling thread
+
+ See MSDN docs on ReleaseSemaphore for all other parameters
+--*/
+
+PAL_ERROR
+CorUnix::InternalReleaseSemaphore(
+ CPalThread *pthr,
+ HANDLE hSemaphore,
+ LONG lReleaseCount,
+ LPLONG lpPreviousCount
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ ISynchStateController *pssc = NULL;
+ SemaphoreImmutableData *pSemaphoreData;
+ LONG lOldCount;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("InternalReleaseSempahore(pthr=%p, hSemaphore=%p, lReleaseCount=%d, "
+ "lpPreviousCount=%p)\n",
+ pthr,
+ hSemaphore,
+ lReleaseCount,
+ lpPreviousCount
+ );
+
+ if (0 >= lReleaseCount)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthr,
+ hSemaphore,
+ &aotSempahore,
+ 0, // Should be SEMAPHORE_MODIFY_STATE; currently ignored (no Win32 security)
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain object for handle %p (error %d)!\n", hSemaphore, palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining object data\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining synch state controller\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pssc->GetSignalCount(&lOldCount);
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining current signal count\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ _ASSERTE(lOldCount <= pSemaphoreData->lMaximumCount);
+ if (lReleaseCount > pSemaphoreData->lMaximumCount - lOldCount)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pssc->IncrementSignalCount(lReleaseCount);
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d incrementing signal count\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ if (NULL != lpPreviousCount)
+ {
+ *lpPreviousCount = lOldCount;
+ }
+
+InternalReleaseSemaphoreExit:
+
+ if (NULL != pssc)
+ {
+ pssc->ReleaseController();
+ }
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalReleaseSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+// TODO: Implementation of OpenSemaphoreA() doesn't exist, do we need it? More generally, do we need the A versions at all?
+
+/*++
+Function:
+ OpenSemaphoreW
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to semaphore are not inheritable)
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+OpenSemaphoreW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(OpenSemaphoreW);
+ ENTRY("OpenSemaphoreW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
+ dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("lpName is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenSemaphoreW returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(OpenSemaphoreW);
+
+ return hSemaphore;
+}
+
+/*++
+Function:
+ InternalOpenSemaphore
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to semaphores are not inheritable)
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated semaphore handle
+
+ See MSDN docs on OpenSemaphore for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalOpenSemaphore(
+ CPalThread *pthr,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ CPalString sObjectName(lpName);
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != lpName);
+ _ASSERTE(NULL != phSemaphore);
+
+ ENTRY("InternalOpenSemaphore(pthr=%p, dwDesiredAccess=%d, bInheritHandle=%d, "
+ "lpName=%p, phSemaphore=%p)\n",
+ pthr,
+ dwDesiredAccess,
+ bInheritHandle,
+ phSemaphore
+ );
+
+ palError = g_pObjectManager->LocateObject(
+ pthr,
+ &sObjectName,
+ &aotSempahore,
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->ObtainHandleForObject(
+ pthr,
+ pobjSemaphore,
+ dwDesiredAccess,
+ bInheritHandle,
+ NULL,
+ phSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenSemaphoreExit;
+ }
+
+InternalOpenSemaphoreExit:
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalOpenSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+