Beispiel #1
0
void SharedMemoryManager::RemoveProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader)
{
    _ASSERTE(processDataHeader != nullptr);
    _ASSERTE(IsCreationDeletionProcessLockAcquired());

    if (s_processDataHeaderListHead == processDataHeader)
    {
        s_processDataHeaderListHead = processDataHeader->GetNextInProcessDataHeaderList();
        processDataHeader->SetNextInProcessDataHeaderList(nullptr);
        return;
    }
    for (SharedMemoryProcessDataHeader
            *previous = s_processDataHeaderListHead,
            *current = previous->GetNextInProcessDataHeaderList();
        current != nullptr;
        previous = current, current = current->GetNextInProcessDataHeaderList())
    {
        if (current == processDataHeader)
        {
            previous->SetNextInProcessDataHeaderList(current->GetNextInProcessDataHeaderList());
            current->SetNextInProcessDataHeaderList(nullptr);
            return;
        }
    }
    _ASSERTE(false);
}
Beispiel #2
0
void SharedMemoryManager::AddProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader)
{
    _ASSERTE(processDataHeader != nullptr);
    _ASSERTE(IsCreationDeletionProcessLockAcquired());
    _ASSERTE(processDataHeader->GetNextInProcessDataHeaderList() == nullptr);
    _ASSERTE(FindProcessDataHeader(processDataHeader->GetId()) == nullptr);

    processDataHeader->SetNextInProcessDataHeaderList(s_processDataHeaderListHead);
    s_processDataHeaderListHead = processDataHeader;
}
Beispiel #3
0
void SharedMemoryManager::StaticClose()
{
    // This function could very well be running during abrupt shutdown, and there could still be user threads running.
    // Synchronize the deletion, and don't remove or delete items in the linked list.
    AcquireCreationDeletionProcessLock();
    for (SharedMemoryProcessDataHeader *current = s_processDataHeaderListHead;
        current != nullptr;
        current = current->GetNextInProcessDataHeaderList())
    {
        current->Close();
    }
    ReleaseCreationDeletionProcessLock();

    // This function could very well be running during abrupt shutdown, and there could still be user threads running. Don't
    // delete the creation/deletion process lock, the process is shutting down anyway.
}
Beispiel #4
0
SharedMemoryProcessDataHeader *SharedMemoryManager::FindProcessDataHeader(SharedMemoryId *id)
{
    _ASSERTE(IsCreationDeletionProcessLockAcquired());

    // TODO: Use a hash table
    for (SharedMemoryProcessDataHeader *current = s_processDataHeaderListHead;
        current != nullptr;
        current = current->GetNextInProcessDataHeaderList())
    {
        if (current->GetId()->Equals(id))
        {
            return current;
        }
    }
    return nullptr;
}
Beispiel #5
0
void SharedMemoryProcessDataHeader::PalObject_Close(
    CPalThread *thread,
    IPalObject *object,
    bool isShuttingDown,
    bool cleanUpPalSharedState)
{
    // This function's signature matches OBJECTCLEANUPROUTINE
    _ASSERTE(thread != nullptr);
    _ASSERTE(object != nullptr);
    _ASSERTE(object->GetObjectType()->GetId() == otiNamedMutex);
    _ASSERTE(object->GetObjectType()->GetImmutableDataSize() == sizeof(SharedMemoryProcessDataHeader *));

    SharedMemoryProcessDataHeader *processDataHeader = PalObject_GetProcessDataHeader(object);
    if (processDataHeader == nullptr)
    {
        // The object was created, but an error must have occurred before the process data was initialized
        return;
    }

    SharedMemoryManager::AcquireCreationDeletionProcessLock();
    processDataHeader->DecRefCount();
    SharedMemoryManager::ReleaseCreationDeletionProcessLock();
}
Beispiel #6
0
        ~AutoCleanup()
        {
        #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
            if (!m_cancel)
            {
                if (m_lockFileDescriptor != -1)
                {
                    SharedMemoryHelpers::CloseFile(m_lockFileDescriptor);
                }

                if (m_createdLockFile)
                {
                    _ASSERTE(m_lockFilePath != nullptr);
                    unlink(m_lockFilePath);
                }

                if (m_sessionDirectoryPathCharCount != 0)
                {
                    _ASSERTE(m_lockFilePath != nullptr);
                    m_lockFilePath[m_sessionDirectoryPathCharCount] = '\0';
                    rmdir(m_lockFilePath);
                }
            }
        #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX

            if (m_acquiredCreationDeletionFileLock)
            {
                SharedMemoryManager::ReleaseCreationDeletionFileLock();
            }

            if (!m_cancel && m_processDataHeader != nullptr)
            {
                _ASSERTE(m_acquiredCreationDeletionProcessLock);
                m_processDataHeader->DecRefCount();
            }

            if (m_acquiredCreationDeletionProcessLock)
            {
                SharedMemoryManager::ReleaseCreationDeletionProcessLock();
            }
        }
Beispiel #7
0
SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::CreateOrOpen(
    LPCSTR name,
    SharedMemorySharedDataHeader requiredSharedDataHeader,
    SIZE_T sharedDataByteCount,
    bool createIfNotExist,
    bool *createdRef)
{
    _ASSERTE(name != nullptr);
    _ASSERTE(sharedDataByteCount != 0);
    _ASSERTE(!createIfNotExist || createdRef != nullptr);
    _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
    _ASSERTE(!SharedMemoryManager::IsCreationDeletionFileLockAcquired());

    if (createdRef != nullptr)
    {
        *createdRef = false;
    }

    SharedMemoryId id(name);

    struct AutoCleanup
    {
        bool m_acquiredCreationDeletionFileLock;
        char *m_filePath;
        SIZE_T m_sessionDirectoryPathCharCount;
        bool m_createdFile;
        int m_fileDescriptor;
        bool m_acquiredFileLock;
        void *m_mappedBuffer;
        SIZE_T m_mappedBufferByteCount;
        bool m_cancel;

        AutoCleanup()
            : m_acquiredCreationDeletionFileLock(false),
            m_filePath(nullptr),
            m_sessionDirectoryPathCharCount(0),
            m_createdFile(false),
            m_fileDescriptor(-1),
            m_acquiredFileLock(false),
            m_mappedBuffer(nullptr),
            m_mappedBufferByteCount(0),
            m_cancel(false)
        {
        }

        ~AutoCleanup()
        {
            if (m_cancel)
            {
                return;
            }

            if (m_mappedBuffer != nullptr)
            {
                _ASSERTE(m_mappedBufferByteCount != 0);
                munmap(m_mappedBuffer, m_mappedBufferByteCount);
            }

            if (m_acquiredFileLock)
            {
                _ASSERTE(m_fileDescriptor != -1);
                SharedMemoryHelpers::ReleaseFileLock(m_fileDescriptor);
            }

            if (m_fileDescriptor != -1)
            {
                SharedMemoryHelpers::CloseFile(m_fileDescriptor);
            }

            if (m_createdFile)
            {
                _ASSERTE(m_filePath != nullptr);
                unlink(m_filePath);
            }

            if (m_sessionDirectoryPathCharCount != 0)
            {
                _ASSERTE(m_filePath != nullptr);
                m_filePath[m_sessionDirectoryPathCharCount] = '\0';
                rmdir(m_filePath);
            }

            if (m_acquiredCreationDeletionFileLock)
            {
                SharedMemoryManager::ReleaseCreationDeletionFileLock();
            }
        }
    } autoCleanup;

    SharedMemoryProcessDataHeader *processDataHeader = SharedMemoryManager::FindProcessDataHeader(&id);
    if (processDataHeader != nullptr)
    {
        _ASSERTE(
            processDataHeader->GetSharedDataTotalByteCount() ==
            SharedMemorySharedDataHeader::DetermineTotalByteCount(sharedDataByteCount));
        processDataHeader->IncRefCount();
        return processDataHeader;
    }

    SharedMemoryManager::AcquireCreationDeletionFileLock();
    autoCleanup.m_acquiredCreationDeletionFileLock = true;

    // Create the session directory
    char filePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
    SIZE_T filePathCharCount = SharedMemoryHelpers::CopyString(filePath, 0, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH);
    filePath[filePathCharCount++] = '/';
    filePathCharCount = id.AppendSessionDirectoryName(filePath, filePathCharCount);
    if (!SharedMemoryHelpers::EnsureDirectoryExists(filePath, true /* isGlobalLockAcquired */, createIfNotExist))
    {
        _ASSERTE(!createIfNotExist);
        return nullptr;
    }
    autoCleanup.m_filePath = filePath;
    autoCleanup.m_sessionDirectoryPathCharCount = filePathCharCount;

    // Create or open the shared memory file
    filePath[filePathCharCount++] = '/';
    filePathCharCount = SharedMemoryHelpers::CopyString(filePath, filePathCharCount, id.GetName(), id.GetNameCharCount());
    bool createdFile;
    int fileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(filePath, createIfNotExist, &createdFile);
    if (fileDescriptor == -1)
    {
        _ASSERTE(!createIfNotExist);
        return nullptr;
    }
    autoCleanup.m_createdFile = createdFile;
    autoCleanup.m_fileDescriptor = fileDescriptor;

    bool clearContents = false;
    if (!createdFile)
    {
        // A shared file lock on the shared memory file would be held by any process that has opened the same file. Try to take
        // an exclusive lock on the file. Successfully acquiring an exclusive lock indicates that no process has a reference to
        // the shared memory file, and this process can reinitialize its contents.
        if (SharedMemoryHelpers::TryAcquireFileLock(fileDescriptor, LOCK_EX | LOCK_NB))
        {
            // The shared memory file is not being used, flag it as created so that its contents will be reinitialized
            SharedMemoryHelpers::ReleaseFileLock(fileDescriptor);
            autoCleanup.m_createdFile = true;
            if (!createIfNotExist)
            {
                return nullptr;
            }
            createdFile = true;
            clearContents = true;
        }
    }

    // Set or validate the file length
    SIZE_T sharedDataTotalByteCount = SharedMemorySharedDataHeader::DetermineTotalByteCount(sharedDataByteCount);
    if (createdFile)
    {
        SharedMemoryHelpers::SetFileSize(fileDescriptor, sharedDataTotalByteCount);
    }
    else if (SharedMemoryHelpers::GetFileSize(fileDescriptor) != sharedDataTotalByteCount)
    {
        throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::HeaderMismatch));
    }

    // Acquire and hold a shared file lock on the shared memory file as long as it is open, to indicate that this process is
    // using the file. An exclusive file lock is attempted above to detect whether the file contents are valid, for the case
    // where a process crashes or is killed after the file is created. Since we already hold the creation/deletion locks, a
    // non-blocking file lock should succeed.
    if (!SharedMemoryHelpers::TryAcquireFileLock(fileDescriptor, LOCK_SH | LOCK_NB))
    {
        throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
    }
    autoCleanup.m_acquiredFileLock = true;

    // Map the file into memory, and initialize or validate the header
    void *mappedBuffer = SharedMemoryHelpers::MemoryMapFile(fileDescriptor, sharedDataTotalByteCount);
    autoCleanup.m_mappedBuffer = mappedBuffer;
    autoCleanup.m_mappedBufferByteCount = sharedDataTotalByteCount;
    SharedMemorySharedDataHeader *sharedDataHeader;
    if (createdFile)
    {
        if (clearContents)
        {
            memset(mappedBuffer, 0, sharedDataTotalByteCount);
        }
        sharedDataHeader = new(mappedBuffer) SharedMemorySharedDataHeader(requiredSharedDataHeader);
    }
    else
    {
        sharedDataHeader = reinterpret_cast<SharedMemorySharedDataHeader *>(mappedBuffer);
        if (sharedDataHeader->GetType() != requiredSharedDataHeader.GetType() ||
            sharedDataHeader->GetVersion() != requiredSharedDataHeader.GetVersion())
        {
            throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::HeaderMismatch));
        }
    }

    // When *createdRef is true, the creation/deletion file lock will remain locked upon returning for the caller to initialize
    // the shared data. The caller must release the file lock afterwards.
    if (!createdFile)
    {
        autoCleanup.m_acquiredCreationDeletionFileLock = false;
        SharedMemoryManager::ReleaseCreationDeletionFileLock();
    }

    processDataHeader = SharedMemoryProcessDataHeader::New(&id, fileDescriptor, sharedDataHeader, sharedDataTotalByteCount);

    autoCleanup.m_cancel = true;
    if (createdFile)
    {
        _ASSERTE(createIfNotExist);
        _ASSERTE(createdRef != nullptr);
        *createdRef = true;
    }
    return processDataHeader;
}
Beispiel #8
0
DWORD CorUnix::InternalWaitForMultipleObjectsEx(
    CPalThread * pThread,
    DWORD nCount,
    CONST HANDLE *lpHandles,
    BOOL bWaitAll,
    DWORD dwMilliseconds,
    BOOL bAlertable)
{
    DWORD dwRet = WAIT_FAILED;
    PAL_ERROR palErr = NO_ERROR;
    int i, iSignaledObjCount, iSignaledObjIndex = -1;
    bool fWAll = (bool)bWaitAll, fNeedToBlock  = false;    
    bool fAbandoned = false;
    WaitType wtWaitType;

    IPalObject            * pIPalObjStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
    ISynchWaitController  * pISyncStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
    IPalObject           ** ppIPalObjs = pIPalObjStackArray;
    ISynchWaitController ** ppISyncWaitCtrlrs = pISyncStackArray;
  
    if ((nCount == 0) || (nCount > MAXIMUM_WAIT_OBJECTS))
    {
        ppIPalObjs = NULL;        // make delete at the end safe
        ppISyncWaitCtrlrs = NULL; // make delete at the end safe       
        ERROR("Invalid object count=%d [range: 1 to %d]\n", 
               nCount, MAXIMUM_WAIT_OBJECTS)
        pThread->SetLastError(ERROR_INVALID_PARAMETER);
        goto WFMOExIntExit;
    }
    else if (nCount == 1)
    {
        fWAll = false;  // makes no difference when nCount is 1
        wtWaitType = SingleObject;                                  
    }
    else 
    {
        wtWaitType = fWAll ? MultipleObjectsWaitAll : MultipleObjectsWaitOne;
        if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
        {
            ppIPalObjs = InternalNewArray<IPalObject*>(nCount);
            ppISyncWaitCtrlrs = InternalNewArray<ISynchWaitController*>(nCount);
            if ((NULL == ppIPalObjs) || (NULL == ppISyncWaitCtrlrs))
            {
                ERROR("Out of memory allocating internal structures\n");
                pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                goto WFMOExIntExit;
            }
        }
    }
   
    palErr = g_pObjectManager->ReferenceMultipleObjectsByHandleArray(pThread,
                                                                     (VOID **)lpHandles, 
                                                                     nCount,
                                                                     &sg_aotWaitObject,
                                                                     SYNCHRONIZE,
                                                                     ppIPalObjs);
    if (NO_ERROR != palErr)
    {
        ERROR("Unable to obtain object for some or all of the handles [error=%u]\n",
              palErr);
        if (palErr == ERROR_INVALID_HANDLE)
            pThread->SetLastError(ERROR_INVALID_HANDLE);
        else
            pThread->SetLastError(ERROR_INTERNAL_ERROR);
        goto WFMOExIntExit;
    }

    if (nCount > 1)
    {
        // Check for any cross-process sync objects. "Wait for any" and "wait for all" operations are not supported on
        // cross-process sync objects in the PAL.
        for (DWORD i = 0; i < nCount; ++i)
        {
            if (ppIPalObjs[i]->GetObjectType()->GetId() == otiNamedMutex)
            {
                ERROR("Attempt to wait for any or all handles including a cross-process sync object", ERROR_NOT_SUPPORTED);
                pThread->SetLastError(ERROR_NOT_SUPPORTED);
                goto WFMOExIntCleanup;
            }
        }
    }
    else if (ppIPalObjs[0]->GetObjectType()->GetId() == otiNamedMutex)
    {
        SharedMemoryProcessDataHeader *processDataHeader =
            SharedMemoryProcessDataHeader::PalObject_GetProcessDataHeader(ppIPalObjs[0]);
        _ASSERTE(processDataHeader != nullptr);
        try
        {
            MutexTryAcquireLockResult tryAcquireLockResult =
                static_cast<NamedMutexProcessData *>(processDataHeader->GetData())->TryAcquireLock(dwMilliseconds);
            switch (tryAcquireLockResult)
            {
                case MutexTryAcquireLockResult::AcquiredLock:
                    dwRet = WAIT_OBJECT_0;
                    break;

                case MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned:
                    dwRet = WAIT_ABANDONED_0;
                    break;

                case MutexTryAcquireLockResult::TimedOut:
                    dwRet = WAIT_TIMEOUT;
                    break;

                default:
                    _ASSERTE(false);
                    break;
            }
        }
        catch (SharedMemoryException ex)
        {
            pThread->SetLastError(ex.GetErrorCode());
        }
        goto WFMOExIntCleanup;
    }

    if (fWAll)
    {
        // For a wait-all operation, check for duplicate wait objects in the array. This just uses a brute-force O(n^2)
        // algorithm, but since MAXIMUM_WAIT_OBJECTS is small, the worst case is not so bad, and the average case would involve
        // significantly fewer items.
        for (DWORD i = 0; i < nCount - 1; ++i)
        {
            IPalObject *const objectToCheck = ppIPalObjs[i];
            for (DWORD j = i + 1; j < nCount; ++j)
            {
                if (ppIPalObjs[j] == objectToCheck)
                {
                    ERROR("Duplicate handle provided for a wait-all operation [error=%u]\n", ERROR_INVALID_PARAMETER);
                    pThread->SetLastError(ERROR_INVALID_PARAMETER);
                    goto WFMOExIntCleanup;
                }
            }
        }
    }

    palErr = g_pSynchronizationManager->GetSynchWaitControllersForObjects(
        pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs);    
    if (NO_ERROR != palErr)
    {
        ERROR("Unable to obtain ISynchWaitController interface for some or all "
              "of the objects [error=%u]\n", palErr);
        pThread->SetLastError(ERROR_INTERNAL_ERROR);
        goto WFMOExIntCleanup;
    }

    if (bAlertable)
    {       
        // First check for pending APC. We need to do that while holding the global
        // synch lock implicitely grabbed by GetSynchWaitControllersForObjects
        if (g_pSynchronizationManager->AreAPCsPending(pThread))
        {
            // If there is any pending APC we need to release the
            // implicit global synch lock before calling into it
            for (i = 0; (i < (int)nCount) && (NULL != ppISyncWaitCtrlrs[i]); i++)    
            {
                ppISyncWaitCtrlrs[i]->ReleaseController();
                ppISyncWaitCtrlrs[i] = NULL;
            }
            palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);
            if (NO_ERROR == palErr)
            {
                dwRet = WAIT_IO_COMPLETION;
            }
            else
            {
                ASSERT("Awakened for APC, but no APC is pending\n");
                pThread->SetLastError(ERROR_INTERNAL_ERROR);
                dwRet = WAIT_FAILED;
            }
            goto WFMOExIntCleanup;
        }
    }    
     
    iSignaledObjCount = 0;
    iSignaledObjIndex = -1;
    for (i=0;i<(int)nCount;i++)
    {
        bool fValue;
        palErr = ppISyncWaitCtrlrs[i]->CanThreadWaitWithoutBlocking(&fValue, &fAbandoned);
        if (NO_ERROR != palErr)
        {
            ERROR("ISynchWaitController::CanThreadWaitWithoutBlocking() failed for "
                  "%d-th object [handle=%p error=%u]\n", i, lpHandles[i], palErr);
            pThread->SetLastError(ERROR_INTERNAL_ERROR);
            goto WFMOExIntReleaseControllers;            
        }
        if (fValue)
        {
            iSignaledObjCount++;
            iSignaledObjIndex = i;
            if (!fWAll)
                break;
        }                
    }

    fNeedToBlock = (iSignaledObjCount == 0) || (fWAll && (iSignaledObjCount < (int)nCount));
    if (!fNeedToBlock)
    {
        // At least one object signaled, or bWaitAll==TRUE and all object signaled.
        // No need to wait, let's unsignal the object(s) and return without blocking        
        int iStartIdx, iEndIdx;
        
        if (fWAll)
        {
            iStartIdx = 0;
            iEndIdx = nCount;
        }
        else
        {
            iStartIdx = iSignaledObjIndex;
            iEndIdx = iStartIdx + 1;
        }
        
        // Unsignal objects
        if( iStartIdx < 0 )
        {
            ERROR("Buffer underflow due to iStartIdx < 0");
            pThread->SetLastError(ERROR_INTERNAL_ERROR);
            dwRet = WAIT_FAILED;
            goto WFMOExIntCleanup;
        }
        for (i = iStartIdx; i < iEndIdx; i++)
        {
            palErr = ppISyncWaitCtrlrs[i]->ReleaseWaitingThreadWithoutBlocking();
            if (NO_ERROR != palErr)
            {     
                ERROR("ReleaseWaitingThreadWithoutBlocking() failed for %d-th "
                      "object [handle=%p error=%u]\n", 
                      i, lpHandles[i], palErr);
                pThread->SetLastError(palErr);
                goto WFMOExIntReleaseControllers;
            }
        }

        dwRet = (fAbandoned ? WAIT_ABANDONED_0 : WAIT_OBJECT_0);
    }
    else if (0 == dwMilliseconds)
    {
        // Not enough objects signaled, but timeout is zero: no actual wait
        dwRet = WAIT_TIMEOUT;
        fNeedToBlock = false;
    }                
    else
    {
        // Register the thread for waiting on all objects
        for (i=0;i<(int)nCount;i++)
        {
            palErr = ppISyncWaitCtrlrs[i]->RegisterWaitingThread(
                                                        wtWaitType, 
                                                        i,
                                                        (TRUE == bAlertable));
            if (NO_ERROR != palErr)
            {               
                ERROR("RegisterWaitingThread() failed for %d-th object "
                      "[handle=%p error=%u]\n", i, lpHandles[i], palErr);
                pThread->SetLastError(palErr);
                goto WFMOExIntReleaseControllers;
            }
        } 
    }

WFMOExIntReleaseControllers:
    // Release all controllers before going to sleep    
    for (i = 0; i < (int)nCount; i++)    
    {
        ppISyncWaitCtrlrs[i]->ReleaseController();
        ppISyncWaitCtrlrs[i] = NULL;
    }
    if (NO_ERROR != palErr)
        goto WFMOExIntCleanup;

    if (fNeedToBlock)
    {
        ThreadWakeupReason twrWakeupReason;

        //
        // Going to sleep
        //
        palErr = g_pSynchronizationManager->BlockThread(pThread, 
                                                        dwMilliseconds, 
                                                        (TRUE == bAlertable), 
                                                        false,
                                                        &twrWakeupReason, 
                                                        (DWORD *)&iSignaledObjIndex);
        //
        // Awakened
        //
        if (NO_ERROR != palErr)
        {     
            ERROR("IPalSynchronizationManager::BlockThread failed for thread "
                  "pThread=%p [error=%u]\n", pThread, palErr);
            pThread->SetLastError(palErr);
            goto WFMOExIntCleanup;
        }
        switch (twrWakeupReason)       
        {
        case WaitSucceeded:
            dwRet = WAIT_OBJECT_0; // offset added later
            break;
        case MutexAbondoned:
            dwRet =  WAIT_ABANDONED_0; // offset added later
            break;
        case WaitTimeout:
            dwRet = WAIT_TIMEOUT;
            break;                
        case Alerted:
            _ASSERT_MSG(bAlertable, 
                        "Awakened for APC from a non-alertable wait\n");

            dwRet = WAIT_IO_COMPLETION;                
            palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);

            _ASSERT_MSG(NO_ERROR == palErr, 
                        "Awakened for APC, but no APC is pending\n");
            break;
        case WaitFailed:
        default:
            ERROR("Thread %p awakened with some failure\n", pThread);
            dwRet = WAIT_FAILED;                
            break;
        }
    }           
    
    if (!fWAll && ((WAIT_OBJECT_0 == dwRet) || (WAIT_ABANDONED_0 == dwRet)))
    {
        _ASSERT_MSG(0 <= iSignaledObjIndex,
                    "Failed to identify signaled/abandoned object\n"); 
        _ASSERT_MSG(iSignaledObjIndex >= 0 && nCount > static_cast<DWORD>(iSignaledObjIndex),
                    "SignaledObjIndex object out of range "
                    "[index=%d obj_count=%u\n", 
                    iSignaledObjCount, nCount);

        if (iSignaledObjIndex < 0)
        {
            pThread->SetLastError(ERROR_INTERNAL_ERROR);
            dwRet = WAIT_FAILED;
            goto WFMOExIntCleanup;
        }
        dwRet += iSignaledObjIndex;
    }

WFMOExIntCleanup:
    for (i = 0; i < (int)nCount; i++)
    {
        ppIPalObjs[i]->ReleaseReference(pThread);
        ppIPalObjs[i] = NULL;
    }
    
WFMOExIntExit:
    if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
    {
        InternalDeleteArray(ppIPalObjs);
        InternalDeleteArray(ppISyncWaitCtrlrs);
    }
    
    return dwRet;
}
Beispiel #9
0
PAL_ERROR
CorUnix::InternalReleaseMutex(
    CPalThread *pthr,
    HANDLE hMutex
    )
{
    PAL_ERROR palError = NO_ERROR;
    IPalObject *pobjMutex = NULL;
    ISynchStateController *pssc = NULL;
    PalObjectTypeId objectTypeId;

    _ASSERTE(NULL != pthr);

    ENTRY("InternalReleaseMutex(pthr=%p, hMutex=%p)\n",
        pthr,
        hMutex
        );

    palError = g_pObjectManager->ReferenceObjectByHandle(
        pthr,
        hMutex,
        &aotAnyMutex,
        0, // should be MUTEX_MODIFY_STATE -- current ignored (no Win32 security)
        &pobjMutex
        );

    if (NO_ERROR != palError)
    {
        ERROR("Unable to obtain object for handle %p (error %d)!\n", hMutex, palError);
        goto InternalReleaseMutexExit;
    }

    objectTypeId = pobjMutex->GetObjectType()->GetId();
    if (objectTypeId == otiMutex)
    {
        palError = pobjMutex->GetSynchStateController(
            pthr,
            &pssc
            );

        if (NO_ERROR != palError)
        {
            ASSERT("Error %d obtaining synch state controller\n", palError);
            goto InternalReleaseMutexExit;
        }

        palError = pssc->DecrementOwnershipCount();

        if (NO_ERROR != palError)
        {
            ERROR("Error %d decrementing mutex ownership count\n", palError);
            goto InternalReleaseMutexExit;
        }
    }
    else
    {
        _ASSERTE(objectTypeId == otiNamedMutex);

        SharedMemoryProcessDataHeader *processDataHeader =
            SharedMemoryProcessDataHeader::PalObject_GetProcessDataHeader(pobjMutex);
        _ASSERTE(processDataHeader != nullptr);
        try
        {
            static_cast<NamedMutexProcessData *>(processDataHeader->GetData())->ReleaseLock();
        }
        catch (SharedMemoryException ex)
        {
            palError = ex.GetErrorCode();
            goto InternalReleaseMutexExit;
        }
    }

InternalReleaseMutexExit:

    if (NULL != pssc)
    {
        pssc->ReleaseController();
    }

    if (NULL != pobjMutex)
    {
        pobjMutex->ReleaseReference(pthr);
    }

    LOGEXIT("InternalReleaseMutex returns %i\n", palError);

    return palError;
}
Beispiel #10
0
SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen(
    LPCSTR name,
    bool createIfNotExist,
    bool acquireLockIfCreated,
    bool *createdRef)
{
    _ASSERTE(name != nullptr);
    _ASSERTE(createIfNotExist || !acquireLockIfCreated);

    struct AutoCleanup
    {
        bool m_acquiredCreationDeletionProcessLock;
        bool m_acquiredCreationDeletionFileLock;
        SharedMemoryProcessDataHeader *m_processDataHeader;
    #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
        char *m_lockFilePath;
        SIZE_T m_sessionDirectoryPathCharCount;
        bool m_createdLockFile;
        int m_lockFileDescriptor;
    #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
        bool m_cancel;

        AutoCleanup()
            : m_acquiredCreationDeletionProcessLock(false),
            m_acquiredCreationDeletionFileLock(false),
            m_processDataHeader(nullptr),
        #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
            m_lockFilePath(nullptr),
            m_sessionDirectoryPathCharCount(0),
            m_createdLockFile(false),
            m_lockFileDescriptor(-1),
        #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
            m_cancel(false)
        {
        }

        ~AutoCleanup()
        {
        #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
            if (!m_cancel)
            {
                if (m_lockFileDescriptor != -1)
                {
                    SharedMemoryHelpers::CloseFile(m_lockFileDescriptor);
                }

                if (m_createdLockFile)
                {
                    _ASSERTE(m_lockFilePath != nullptr);
                    unlink(m_lockFilePath);
                }

                if (m_sessionDirectoryPathCharCount != 0)
                {
                    _ASSERTE(m_lockFilePath != nullptr);
                    m_lockFilePath[m_sessionDirectoryPathCharCount] = '\0';
                    rmdir(m_lockFilePath);
                }
            }
        #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX

            if (m_acquiredCreationDeletionFileLock)
            {
                SharedMemoryManager::ReleaseCreationDeletionFileLock();
            }

            if (!m_cancel && m_processDataHeader != nullptr)
            {
                _ASSERTE(m_acquiredCreationDeletionProcessLock);
                m_processDataHeader->DecRefCount();
            }

            if (m_acquiredCreationDeletionProcessLock)
            {
                SharedMemoryManager::ReleaseCreationDeletionProcessLock();
            }
        }
    } autoCleanup;

    SharedMemoryManager::AcquireCreationDeletionProcessLock();
    autoCleanup.m_acquiredCreationDeletionProcessLock = true;

    // Create or open the shared memory
    bool created;
    SharedMemoryProcessDataHeader *processDataHeader =
        SharedMemoryProcessDataHeader::CreateOrOpen(
            name,
            SharedMemorySharedDataHeader(SharedMemoryType::Mutex, SyncSystemVersion),
            sizeof(NamedMutexSharedData),
            createIfNotExist,
            &created);
    if (createdRef != nullptr)
    {
        *createdRef = created;
    }
    if (created)
    {
        // If the shared memory file was created, the creation/deletion file lock would have been acquired so that we can
        // initialize the shared data
        autoCleanup.m_acquiredCreationDeletionFileLock = true;
    }
    if (processDataHeader == nullptr)
    {
        _ASSERTE(!createIfNotExist);
        return nullptr;
    }
    autoCleanup.m_processDataHeader = processDataHeader;

    if (created)
    {
        // Initialize the shared data
        new(processDataHeader->GetSharedDataHeader()->GetData()) NamedMutexSharedData;
    }

    if (processDataHeader->GetData() == nullptr)
    {
    #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
        // Create the lock files directory
        char lockFilePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
        SIZE_T lockFilePathCharCount =
            SharedMemoryHelpers::CopyString(lockFilePath, 0, SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH);
        if (created)
        {
            SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */);
        }

        // Create the session directory
        lockFilePath[lockFilePathCharCount++] = '/';
        SharedMemoryId *id = processDataHeader->GetId();
        lockFilePathCharCount = id->AppendSessionDirectoryName(lockFilePath, lockFilePathCharCount);
        if (created)
        {
            SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */);
            autoCleanup.m_lockFilePath = lockFilePath;
            autoCleanup.m_sessionDirectoryPathCharCount = lockFilePathCharCount;
        }

        // Create or open the lock file
        lockFilePath[lockFilePathCharCount++] = '/';
        lockFilePathCharCount =
            SharedMemoryHelpers::CopyString(lockFilePath, lockFilePathCharCount, id->GetName(), id->GetNameCharCount());
        int lockFileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(lockFilePath, created);
        if (lockFileDescriptor == -1)
        {
            _ASSERTE(!created);
            if (createIfNotExist)
            {
                throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
            }
            return nullptr;
        }
        autoCleanup.m_createdLockFile = created;
        autoCleanup.m_lockFileDescriptor = lockFileDescriptor;
    #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX

        // Create the process data
        void *processDataBuffer = SharedMemoryHelpers::Alloc(sizeof(NamedMutexProcessData));
        AutoFreeBuffer autoFreeProcessDataBuffer(processDataBuffer);
        NamedMutexProcessData *processData =
            new(processDataBuffer)
            NamedMutexProcessData(
                processDataHeader
            #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
                ,
                lockFileDescriptor
            #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
            );
        autoFreeProcessDataBuffer.Cancel();
        processDataHeader->SetData(processData);

        // If the mutex was created and if requested, acquire the lock initially while holding the creation/deletion locks
        if (created && acquireLockIfCreated)
        {
            MutexTryAcquireLockResult tryAcquireLockResult = processData->TryAcquireLock(0);
            _ASSERTE(tryAcquireLockResult == MutexTryAcquireLockResult::AcquiredLock);
        }
    }

    autoCleanup.m_cancel = true;
    return processDataHeader;
}