2
0
Эх сурвалжийг харах

xplat: implement semaphore

Oguz Bastemur 8 жил өмнө
parent
commit
4bed24070b

+ 0 - 17
bin/ch/RuntimeThreadData.cpp

@@ -4,22 +4,6 @@
 //-------------------------------------------------------------------------------------------------------
 #include "stdafx.h"
 
-#ifndef _WIN32
-HANDLE CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCWSTR lpName)
-{
-    // xplat-todo: implement this in PAL
-    Assert(false);
-    return INVALID_HANDLE_VALUE;
-}
-BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount)
-{
-    // xplat-todo: implement this in PAL
-    Assert(false);
-    return FALSE;
-}
-
-#endif
-
 void RuntimeThreadLocalData::Initialize(RuntimeThreadData* threadData)
 {
     this->threadData = threadData;
@@ -29,7 +13,6 @@ void RuntimeThreadLocalData::Uninitialize()
 {
 }
 
-
 THREAD_LOCAL RuntimeThreadLocalData threadLocalData;
 
 RuntimeThreadLocalData& GetRuntimeThreadLocalData()

+ 1 - 0
pal/src/CMakeLists.txt

@@ -158,6 +158,7 @@ set(SOURCES
   shmemory/shmemory.cpp
   synchobj/event.cpp
   synchobj/mutex.cpp
+  synchobj/semaphore.cpp
   synchmgr/synchcontrollers.cpp
   synchmgr/synchmanager.cpp
   synchmgr/wait.cpp

+ 60 - 0
pal/src/include/pal/semaphore.hpp

@@ -0,0 +1,60 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// 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.hpp
+
+Abstract:
+
+    Semaphore object structure definition.
+
+
+
+--*/
+
+#ifndef _PAL_SEMAPHORE_H_
+#define _PAL_SEMAPHORE_H_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+    extern CObjectType otSemaphore;
+
+    typedef struct
+    {
+        LONG lMaximumCount;
+    } SemaphoreImmutableData;
+
+    PAL_ERROR
+    InternalCreateSemaphore(
+        CPalThread *pThread,
+        LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+        LONG lInitialCount,
+        LONG lMaximumCount,
+        LPCWSTR lpName,
+        HANDLE *phSemaphore
+        );
+
+    PAL_ERROR
+    InternalReleaseSemaphore(
+        CPalThread *pThread,
+        HANDLE hSemaphore,
+        LONG lReleaseCount,
+        LPLONG lpPreviousCount
+        );
+
+}
+
+#endif //_PAL_SEMAPHORE_H_

+ 604 - 0
pal/src/synchobj/semaphore.cpp

@@ -0,0 +1,604 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// 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),
+                // NULL,   // No immutable data copy routine
+                // NULL,   // No immutable data cleanup routine
+                0,      // No process local data
+                // NULL,   // No process local data cleanup routine
+                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.
+--*/
+
+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
+
+    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;
+}