/*++ Function: InternalResumeThread InternalResumeThread converts the handle of the target thread to a CPalThread, and passes both the resumer and target thread references to InternalResumeThreadFromData. A reference to the suspend count from the resumption attempt is passed back to the caller of this function. --*/ PAL_ERROR CorUnix::InternalResumeThread( CPalThread *pthrResumer, HANDLE hTargetThread, DWORD *pdwSuspendCount ) { PAL_ERROR palError = NO_ERROR; CPalThread *pthrTarget = NULL; IPalObject *pobjThread = NULL; palError = InternalGetThreadDataFromHandle( pthrResumer, hTargetThread, 0, // THREAD_SUSPEND_RESUME &pthrTarget, &pobjThread ); if (NO_ERROR == palError) { palError = pthrResumer->suspensionInfo.InternalResumeThreadFromData( pthrResumer, pthrTarget, pdwSuspendCount ); } if (NULL != pobjThread) { pobjThread->ReleaseReference(pthrResumer); } return palError; }
/*++ Function: GetThreadContext See MSDN doc. --*/ BOOL PALAPI GetThreadContext( IN HANDLE hThread, IN OUT LPCONTEXT lpContext) { PAL_ERROR palError; CPalThread *pThread; CPalThread *pTargetThread; IPalObject *pobjThread = NULL; BOOL ret = FALSE; PERF_ENTRY(GetThreadContext); ENTRY("GetThreadContext (hThread=%p, lpContext=%p)\n",hThread,lpContext); pThread = InternalGetCurrentThread(); palError = InternalGetThreadDataFromHandle( pThread, hThread, 0, // THREAD_GET_CONTEXT &pTargetThread, &pobjThread ); if (NO_ERROR == palError) { if (!pTargetThread->IsDummy()) { ret = CONTEXT_GetThreadContext( GetCurrentProcessId(), pTargetThread->GetPThreadSelf(), lpContext ); } else { ASSERT("Dummy thread handle passed to GetThreadContext\n"); pThread->SetLastError(ERROR_INVALID_HANDLE); } } else { pThread->SetLastError(palError); } if (NULL != pobjThread) { pobjThread->ReleaseReference(pThread); } LOGEXIT("GetThreadContext returns ret:%d\n", ret); PERF_EXIT(GetThreadContext); return ret; }
/*++ Function: QueueUserAPC See MSDN doc. --*/ DWORD PALAPI QueueUserAPC( PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) { CPalThread * pCurrentThread = NULL; CPalThread * pTargetThread = NULL; IPalObject * pTargetThreadObject = NULL; PAL_ERROR palErr; DWORD dwRet; PERF_ENTRY(QueueUserAPC); ENTRY("QueueUserAPC(pfnAPC=%p, hThread=%p, dwData=%#x)\n", pfnAPC, hThread, dwData); /* NOTE: Windows does not check the validity of pfnAPC, even if it is NULL. It just does an access violation later on when the APC call is attempted */ pCurrentThread = InternalGetCurrentThread(); palErr = InternalGetThreadDataFromHandle( pCurrentThread, hThread, 0, // THREAD_SET_CONTEXT &pTargetThread, &pTargetThreadObject ); if (NO_ERROR != palErr) { ERROR("Unable to obtain thread data for handle %p (error %x)!\n", hThread, palErr); goto QueueUserAPC_exit; } palErr = g_pSynchronizationManager->QueueUserAPC(pCurrentThread, pTargetThread, pfnAPC, dwData); QueueUserAPC_exit: if (pTargetThreadObject) { pTargetThreadObject->ReleaseReference(pCurrentThread); } dwRet = (NO_ERROR == palErr) ? 1 : 0; LOGEXIT("QueueUserAPC returns DWORD %d\n", dwRet); PERF_EXIT(QueueUserAPC); return dwRet; }
PAL_ERROR CSimpleHandleManager::FreeHandle( CPalThread *pThread, HANDLE h ) { PAL_ERROR palError = NO_ERROR; IPalObject *pobj = NULL; HANDLE_INDEX hi = HandleToHandleIndex(h); Lock(pThread); if (!ValidateHandle(h)) { ERROR("Trying to free invalid handle %p.\n", h); palError = ERROR_INVALID_HANDLE; goto FreeHandleExit; } if (HandleIsSpecial(h)) { ASSERT("Trying to free Special Handle %p.\n", h); palError = ERROR_INVALID_HANDLE; goto FreeHandleExit; } pobj = m_rghteHandleTable[hi].u.pObject; m_rghteHandleTable[hi].fEntryAllocated = FALSE; /* add handle to the free pool */ if(m_hiFreeListEnd != c_hiInvalid) { m_rghteHandleTable[m_hiFreeListEnd].u.hiNextIndex = hi; } else { m_hiFreeListStart = hi; } m_rghteHandleTable[hi].u.hiNextIndex = c_hiInvalid; m_hiFreeListEnd = hi; FreeHandleExit: Unlock(pThread); if (NULL != pobj) { pobj->ReleaseReference(pThread); } return palError; }
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; }
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; }
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: DBGSetProcessAttached Abstract saves the current process Id in the attached process structure Parameter hProcess : process handle bAttach : true (false) to set the process as attached (as detached) Return returns the number of attachment left on attachedProcId, or -1 if it fails --*/ static int DBGSetProcessAttached( CPalThread *pThread, HANDLE hProcess, BOOL bAttach ) { PAL_ERROR palError = NO_ERROR; IPalObject *pobjProcess = NULL; IDataLock *pDataLock = NULL; CProcProcessLocalData *pLocalData = NULL; int ret = -1; CAllowedObjectTypes aotProcess(otiProcess); palError = g_pObjectManager->ReferenceObjectByHandle( pThread, hProcess, &aotProcess, 0, &pobjProcess ); if (NO_ERROR != palError) { goto DBGSetProcessAttachedExit; } palError = pobjProcess->GetProcessLocalData( pThread, WriteLock, &pDataLock, reinterpret_cast<void **>(&pLocalData) ); if (NO_ERROR != palError) { goto DBGSetProcessAttachedExit; } if (bAttach) { pLocalData->lAttachCount += 1; } else { pLocalData->lAttachCount -= 1; if (pLocalData->lAttachCount < 0) { ASSERT("pLocalData->lAttachCount < 0 check for extra DBGDetachProcess calls\n"); palError = ERROR_INTERNAL_ERROR; goto DBGSetProcessAttachedExit; } } ret = pLocalData->lAttachCount; DBGSetProcessAttachedExit: if (NULL != pDataLock) { pDataLock->ReleaseLock(pThread, TRUE); } if (NULL != pobjProcess) { pobjProcess->ReleaseReference(pThread); } return ret; }
DWORD PAL_DeleteExecWatchpoint( HANDLE hThread, PVOID pvInstruction ) { PERF_ENTRY(PAL_DeleteExecWatchpoint); ENTRY("PAL_DeleteExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction); DWORD dwError = ERROR_NOT_SUPPORTED; #if HAVE_PRWATCH_T CPalThread *pThread = NULL; CPalThread *pTargetThread = NULL; IPalObject *pobjThread = NULL; int fd = -1; char ctlPath[50]; struct { long ctlCode; prwatch_t prwatch; } ctlStruct; pThread = InternalGetCurrentThread(); dwError = InternalGetThreadDataFromHandle( pThread, hThread, 0, // THREAD_SET_CONTEXT &pTargetThread, &pobjThread ); if (NO_ERROR != dwError) { goto PAL_DeleteExecWatchpointExit; } snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId()); fd = InternalOpen(pThread, ctlPath, O_WRONLY); if (-1 == fd) { ERROR("Failed to open %s\n", ctlPath); dwError = ERROR_INVALID_ACCESS; goto PAL_DeleteExecWatchpointExit; } ctlStruct.ctlCode = PCWATCH; ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction; ctlStruct.prwatch.pr_size = sizeof(DWORD); ctlStruct.prwatch.pr_wflags = 0; if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct)) { ERROR("Failure writing control structure (errno = %u)\n", errno); dwError = ERROR_INTERNAL_ERROR; goto PAL_DeleteExecWatchpointExit; } dwError = ERROR_SUCCESS; PAL_DeleteExecWatchpointExit: if (NULL != pobjThread) { pobjThread->ReleaseReference(pThread); } if (-1 != fd) { close(fd); } #endif // HAVE_PRWATCH_T LOGEXIT("PAL_DeleteExecWatchpoint returns ret:%d\n", dwError); PERF_EXIT(PAL_DeleteExecWatchpoint); return dwError; }
PAL_ERROR CorUnix::InternalCreateMutex( CPalThread *pthr, LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName, HANDLE *phMutex ) { CObjectAttributes oa(lpName, lpMutexAttributes); PAL_ERROR palError = NO_ERROR; IPalObject *pobjMutex = NULL; IPalObject *pobjRegisteredMutex = NULL; ISynchStateController *pssc = NULL; _ASSERTE(NULL != pthr); _ASSERTE(NULL != phMutex); ENTRY("InternalCreateMutex(pthr=%p, lpMutexAttributes=%p, bInitialOwner=%d" ", lpName=%p, phMutex=%p)\n", pthr, lpMutexAttributes, bInitialOwner, lpName, phMutex ); if (lpName != nullptr) { ASSERT("lpName: Cross-process named objects are not supported in PAL"); palError = ERROR_NOT_SUPPORTED; goto InternalCreateMutexExit; } palError = g_pObjectManager->AllocateObject( pthr, &otMutex, &oa, &pobjMutex ); if (NO_ERROR != palError) { goto InternalCreateMutexExit; } palError = pobjMutex->GetSynchStateController( pthr, &pssc ); if (NO_ERROR != palError) { ASSERT("Unable to create state controller (%d)\n", palError); goto InternalCreateMutexExit; } if (bInitialOwner) { palError = pssc->SetOwner(pthr); } else { palError = pssc->SetSignalCount(1); } pssc->ReleaseController(); if (NO_ERROR != palError) { ASSERT("Unable to set initial mutex state (%d)\n", palError); goto InternalCreateMutexExit; } palError = g_pObjectManager->RegisterObject( pthr, pobjMutex, &aotMutex, 0, // should be MUTEX_ALL_ACCESS -- currently ignored (no Win32 security) phMutex, &pobjRegisteredMutex ); // // pobjMutex 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. // pobjMutex = NULL; InternalCreateMutexExit: if (NULL != pobjMutex) { pobjMutex->ReleaseReference(pthr); } if (NULL != pobjRegisteredMutex) { pobjRegisteredMutex->ReleaseReference(pthr); } LOGEXIT("InternalCreateMutex returns %i\n", palError); return palError; }
PAL_ERROR CorUnix::InternalGetFileTime( CPalThread *pThread, IN HANDLE hFile, OUT LPFILETIME lpCreationTime, OUT LPFILETIME lpLastAccessTime, OUT LPFILETIME lpLastWriteTime) { PAL_ERROR palError = NO_ERROR; IPalObject *pFileObject = NULL; CFileProcessLocalData *pLocalData = NULL; IDataLock *pLocalDataLock = NULL; int Fd = -1; struct stat StatData; if (INVALID_HANDLE_VALUE == hFile) { ERROR( "Invalid file handle\n" ); palError = ERROR_INVALID_HANDLE; goto InternalGetFileTimeExit; } palError = g_pObjectManager->ReferenceObjectByHandle( pThread, hFile, &aotFile, GENERIC_READ, &pFileObject ); if (NO_ERROR != palError) { goto InternalGetFileTimeExit; } palError = pFileObject->GetProcessLocalData( pThread, ReadLock, &pLocalDataLock, reinterpret_cast<void**>(&pLocalData) ); if (NO_ERROR != palError) { goto InternalGetFileTimeExit; } Fd = pLocalData->unix_fd; if ( Fd == -1 ) { TRACE("pLocalData = [%p], Fd = %d\n", pLocalData, Fd); palError = ERROR_INVALID_HANDLE; goto InternalGetFileTimeExit; } if ( fstat(Fd, &StatData) != 0 ) { TRACE("fstat failed on file descriptor %d\n", Fd); palError = FILEGetLastErrorFromErrno(); goto InternalGetFileTimeExit; } if ( lpCreationTime ) { *lpCreationTime = FILEUnixTimeToFileTime(StatData.st_ctime, ST_CTIME_NSEC(&StatData)); } if ( lpLastWriteTime ) { *lpLastWriteTime = FILEUnixTimeToFileTime(StatData.st_mtime, ST_MTIME_NSEC(&StatData)); } if ( lpLastAccessTime ) { *lpLastAccessTime = FILEUnixTimeToFileTime(StatData.st_atime, ST_ATIME_NSEC(&StatData)); /* if Unix mtime is greater than atime, return mtime as the last access time */ if ( lpLastWriteTime && CompareFileTime(lpLastAccessTime, lpLastWriteTime) < 0 ) { *lpLastAccessTime = *lpLastWriteTime; } } InternalGetFileTimeExit: if (NULL != pLocalDataLock) { pLocalDataLock->ReleaseLock(pThread, FALSE); } if (NULL != pFileObject) { pFileObject->ReleaseReference(pThread); } return palError; }
PAL_ERROR CorUnix::InternalSetFileTime( CPalThread *pThread, IN HANDLE hFile, IN CONST FILETIME *lpCreationTime, IN CONST FILETIME *lpLastAccessTime, IN CONST FILETIME *lpLastWriteTime) { PAL_ERROR palError = NO_ERROR; IPalObject *pFileObject = NULL; CFileProcessLocalData *pLocalData = NULL; IDataLock *pLocalDataLock = NULL; struct timeval Times[2]; int fd; long nsec; struct stat stat_buf; if (INVALID_HANDLE_VALUE == hFile) { ERROR( "Invalid file handle\n" ); palError = ERROR_INVALID_HANDLE; goto InternalSetFileTimeExit; } palError = g_pObjectManager->ReferenceObjectByHandle( pThread, hFile, &aotFile, GENERIC_READ, &pFileObject ); if (NO_ERROR != palError) { goto InternalSetFileTimeExit; } palError = pFileObject->GetProcessLocalData( pThread, ReadLock, &pLocalDataLock, reinterpret_cast<void**>(&pLocalData) ); if (NO_ERROR != palError) { goto InternalSetFileTimeExit; } if (lpCreationTime) { palError = ERROR_NOT_SUPPORTED; goto InternalSetFileTimeExit; } if( !lpLastAccessTime && !lpLastWriteTime ) { // if both pointers are NULL, the function simply returns. goto InternalSetFileTimeExit; } else if( !lpLastAccessTime || !lpLastWriteTime ) { // if either pointer is NULL, fstat will need to be called. fd = pLocalData->unix_fd; if ( fd == -1 ) { TRACE("pLocalData = [%p], fd = %d\n", pLocalData, fd); palError = ERROR_INVALID_HANDLE; goto InternalSetFileTimeExit; } if ( fstat(fd, &stat_buf) != 0 ) { TRACE("fstat failed on file descriptor %d\n", fd); palError = FILEGetLastErrorFromErrno(); goto InternalSetFileTimeExit; } } if (lpLastAccessTime) { Times[0].tv_sec = FILEFileTimeToUnixTime( *lpLastAccessTime, &nsec ); Times[0].tv_usec = nsec / 1000; /* convert to microseconds */ } else { Times[0].tv_sec = stat_buf.st_atime; Times[0].tv_usec = ST_ATIME_NSEC(&stat_buf) / 1000; } if (lpLastWriteTime) { Times[1].tv_sec = FILEFileTimeToUnixTime( *lpLastWriteTime, &nsec ); Times[1].tv_usec = nsec / 1000; /* convert to microseconds */ } else { Times[1].tv_sec = stat_buf.st_mtime; Times[1].tv_usec = ST_MTIME_NSEC(&stat_buf) / 1000; } TRACE("Setting atime = [%ld.%ld], mtime = [%ld.%ld]\n", Times[0].tv_sec, Times[0].tv_usec, Times[1].tv_sec, Times[1].tv_usec); #if HAVE_FUTIMES if ( futimes(pLocalData->unix_fd, Times) != 0 ) #elif HAVE_UTIMES if ( utimes(pLocalData->unix_filename, Times) != 0 ) #else #error Operating system not supported #endif { palError = FILEGetLastErrorFromErrno(); } InternalSetFileTimeExit: if (NULL != pLocalDataLock) { pLocalDataLock->ReleaseLock(pThread, FALSE); } if (NULL != pFileObject) { pFileObject->ReleaseReference(pThread); } return palError; }
PAL_ERROR CorUnix::InternalOpenMutex( CPalThread *pthr, DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName, HANDLE *phMutex ) { CObjectAttributes oa; PAL_ERROR palError = NO_ERROR; IPalObject *pobjMutex = NULL; IPalObject *pobjRegisteredMutex = NULL; HANDLE hMutex = nullptr; _ASSERTE(NULL != pthr); _ASSERTE(NULL != lpName); _ASSERTE(NULL != phMutex); ENTRY("InternalOpenMutex(pthr=%p, dwDesiredAcces=%d, bInheritHandle=%d, " "lpName=%p, phMutex=%p)\n", pthr, dwDesiredAccess, bInheritHandle, lpName, phMutex ); palError = g_pObjectManager->AllocateObject( pthr, &otNamedMutex, &oa, &pobjMutex ); if (NO_ERROR != palError) { goto InternalOpenMutexExit; } palError = g_pObjectManager->RegisterObject( pthr, pobjMutex, &aotNamedMutex, dwDesiredAccess, &hMutex, &pobjRegisteredMutex ); if (palError != NO_ERROR) { _ASSERTE(palError != ERROR_ALREADY_EXISTS); // PAL's naming infrastructure is not used for named mutexes _ASSERTE(pobjRegisteredMutex == nullptr); _ASSERTE(hMutex == nullptr); goto InternalOpenMutexExit; } // Now that the object has been registered successfully, it would have a reference associated with the handle, so release // the initial reference. Any errors from now on need to revoke the handle. _ASSERTE(pobjRegisteredMutex == pobjMutex); _ASSERTE(hMutex != nullptr); pobjMutex->ReleaseReference(pthr); pobjRegisteredMutex = nullptr; { SharedMemoryProcessDataHeader *processDataHeader; try { processDataHeader = NamedMutexProcessData::Open(lpName); } catch (SharedMemoryException ex) { palError = ex.GetErrorCode(); goto InternalOpenMutexExit; } if (processDataHeader == nullptr) { palError = ERROR_FILE_NOT_FOUND; goto InternalOpenMutexExit; } SharedMemoryProcessDataHeader::PalObject_SetProcessDataHeader(pobjMutex, processDataHeader); } *phMutex = hMutex; hMutex = nullptr; pobjMutex = nullptr; InternalOpenMutexExit: _ASSERTE(pobjRegisteredMutex == nullptr); if (hMutex != nullptr) { g_pObjectManager->RevokeHandle(pthr, hMutex); } else if (NULL != pobjMutex) { pobjMutex->ReleaseReference(pthr); } LOGEXIT("InternalCreateMutex returns %i\n", palError); return palError; }
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; }
PAL_ERROR CorUnix::InternalCreateMutex( CPalThread *pthr, LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCSTR lpName, HANDLE *phMutex ) { CObjectAttributes oa(nullptr, lpMutexAttributes); PAL_ERROR palError = NO_ERROR; IPalObject *pobjMutex = NULL; IPalObject *pobjRegisteredMutex = NULL; ISynchStateController *pssc = NULL; HANDLE hMutex = nullptr; _ASSERTE(NULL != pthr); _ASSERTE(NULL != phMutex); ENTRY("InternalCreateMutex(pthr=%p, lpMutexAttributes=%p, bInitialOwner=%d" ", lpName=%p, phMutex=%p)\n", pthr, lpMutexAttributes, bInitialOwner, lpName, phMutex ); if (lpName != nullptr && lpName[0] == '\0') { // Empty name is treated as a request for an unnamed process-local mutex lpName = nullptr; } CObjectType *ot = lpName == nullptr ? &otMutex : &otNamedMutex; CAllowedObjectTypes *aot = lpName == nullptr ? &aotMutex : &aotNamedMutex; palError = g_pObjectManager->AllocateObject( pthr, ot, &oa, &pobjMutex ); if (NO_ERROR != palError) { goto InternalCreateMutexExit; } if (lpName == nullptr) { palError = pobjMutex->GetSynchStateController( pthr, &pssc ); if (NO_ERROR != palError) { ASSERT("Unable to create state controller (%d)\n", palError); goto InternalCreateMutexExit; } if (bInitialOwner) { palError = pssc->SetOwner(pthr); } else { palError = pssc->SetSignalCount(1); } pssc->ReleaseController(); if (NO_ERROR != palError) { ASSERT("Unable to set initial mutex state (%d)\n", palError); goto InternalCreateMutexExit; } } palError = g_pObjectManager->RegisterObject( pthr, pobjMutex, aot, 0, // should be MUTEX_ALL_ACCESS -- currently ignored (no Win32 security) &hMutex, &pobjRegisteredMutex ); if (palError != NO_ERROR) { _ASSERTE(palError != ERROR_ALREADY_EXISTS); // PAL's naming infrastructure is not used for named mutexes _ASSERTE(pobjRegisteredMutex == nullptr); _ASSERTE(hMutex == nullptr); goto InternalCreateMutexExit; } // Now that the object has been registered successfully, it would have a reference associated with the handle, so release // the initial reference. Any errors from now on need to revoke the handle. _ASSERTE(pobjRegisteredMutex == pobjMutex); _ASSERTE(hMutex != nullptr); pobjMutex->ReleaseReference(pthr); pobjRegisteredMutex = nullptr; if (lpName != nullptr) { SharedMemoryProcessDataHeader *processDataHeader; bool created = false; try { processDataHeader = NamedMutexProcessData::CreateOrOpen(lpName, !!bInitialOwner, &created); } catch (SharedMemoryException ex) { palError = ex.GetErrorCode(); goto InternalCreateMutexExit; } SharedMemoryProcessDataHeader::PalObject_SetProcessDataHeader(pobjMutex, processDataHeader); if (!created) { // Indicate to the caller that an existing mutex was opened, and hence the caller will not have initial ownership // of the mutex if requested through bInitialOwner palError = ERROR_ALREADY_EXISTS; } } *phMutex = hMutex; hMutex = nullptr; pobjMutex = nullptr; InternalCreateMutexExit: _ASSERTE(pobjRegisteredMutex == nullptr); if (hMutex != nullptr) { g_pObjectManager->RevokeHandle(pthr, hMutex); } else if (NULL != pobjMutex) { pobjMutex->ReleaseReference(pthr); } LOGEXIT("InternalCreateMutex returns %i\n", palError); return palError; }
PAL_ERROR CorUnix::InternalReleaseMutex( CPalThread *pthr, HANDLE hMutex ) { PAL_ERROR palError = NO_ERROR; IPalObject *pobjMutex = NULL; ISynchStateController *pssc = NULL; _ASSERTE(NULL != pthr); ENTRY("InternalReleaseMutex(pthr=%p, hMutex=%p)\n", pthr, hMutex ); palError = g_pObjectManager->ReferenceObjectByHandle( pthr, hMutex, &aotMutex, 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; } 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; } InternalReleaseMutexExit: if (NULL != pssc) { pssc->ReleaseController(); } if (NULL != pobjMutex) { pobjMutex->ReleaseReference(pthr); } LOGEXIT("InternalReleaseMutex returns %i\n", palError); return palError; }
/*++ Function: _open_osfhandle See MSDN doc. --*/ int __cdecl _open_osfhandle( INT_PTR osfhandle, int flags ) { PAL_ERROR palError = NO_ERROR; CPalThread *pthrCurrent = NULL; IPalObject *pobjFile = NULL; CFileProcessLocalData *pLocalData = NULL; IDataLock *pDataLock = NULL; INT nRetVal = -1; INT openFlags = 0; PERF_ENTRY(_open_osfhandle); ENTRY( "_open_osfhandle (osfhandle=%#x, flags=%#x)\n", osfhandle, flags ); pthrCurrent = InternalGetCurrentThread(); if (flags != _O_RDONLY) { ASSERT("flag(%#x) not supported\n", flags); goto EXIT; } openFlags |= O_RDONLY; palError = g_pObjectManager->ReferenceObjectByHandle( pthrCurrent, reinterpret_cast<HANDLE>(osfhandle), &aotFile, 0, &pobjFile ); if (NO_ERROR != palError) { ERROR("Error dereferencing file handle\n"); goto EXIT; } palError = pobjFile->GetProcessLocalData( pthrCurrent, ReadLock, &pDataLock, reinterpret_cast<void **>(&pLocalData) ); if (NO_ERROR == palError) { if ('\0' != pLocalData->unix_filename[0]) { nRetVal = InternalOpen(pthrCurrent, pLocalData->unix_filename, openFlags); } else /* the only file object with no unix_filename is a pipe */ { /* check if the file pipe descrptor is for read or write */ if (pLocalData->open_flags == O_WRONLY) { ERROR( "Couldn't open a write pipe on read mode\n"); goto EXIT; } nRetVal = pLocalData->unix_fd; } if ( nRetVal == -1 ) { ERROR( "Error: %s.\n", strerror( errno ) ); } } else { ASSERT("Unable to access file data"); } EXIT: if (NULL != pDataLock) { pDataLock->ReleaseLock(pthrCurrent, FALSE); } if (NULL != pobjFile) { pobjFile->ReleaseReference(pthrCurrent); } LOGEXIT( "_open_osfhandle return nRetVal:%d\n", nRetVal); PERF_EXIT(_open_osfhandle); return nRetVal; }
DWORD PAL_CreateExecWatchpoint( HANDLE hThread, PVOID pvInstruction ) { PERF_ENTRY(PAL_CreateExecWatchpoint); ENTRY("PAL_CreateExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction); DWORD dwError = ERROR_NOT_SUPPORTED; #if HAVE_PRWATCH_T CPalThread *pThread = NULL; CPalThread *pTargetThread = NULL; IPalObject *pobjThread = NULL; int fd = -1; char ctlPath[50]; struct { long ctlCode; prwatch_t prwatch; } ctlStruct; // // We must never set a watchpoint on an instruction that enters a syscall; // if such a request comes in we succeed it w/o actually creating the // watchpoint. This mirrors the behavior of setting the single-step flag // in a thread context when the thread is w/in a system service -- the // flag is ignored and will not be present when the thread returns // to user mode. // #if defined(_SPARC_) if (*(DWORD*)pvInstruction == 0x91d02008) // ta 8 { TRACE("Watchpoint requested on sysenter instruction -- ignoring"); dwError = ERROR_SUCCESS; goto PAL_CreateExecWatchpointExit; } #else #error Need syscall instruction for this platform #endif // _SPARC_ pThread = InternalGetCurrentThread(); dwError = InternalGetThreadDataFromHandle( pThread, hThread, 0, // THREAD_SET_CONTEXT &pTargetThread, &pobjThread ); if (NO_ERROR != dwError) { goto PAL_CreateExecWatchpointExit; } snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId()); fd = InternalOpen(pThread, ctlPath, O_WRONLY); if (-1 == fd) { ERROR("Failed to open %s\n", ctlPath); dwError = ERROR_INVALID_ACCESS; goto PAL_CreateExecWatchpointExit; } ctlStruct.ctlCode = PCWATCH; ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction; ctlStruct.prwatch.pr_size = sizeof(DWORD); ctlStruct.prwatch.pr_wflags = WA_EXEC | WA_TRAPAFTER; if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct)) { ERROR("Failure writing control structure (errno = %u)\n", errno); dwError = ERROR_INTERNAL_ERROR; goto PAL_CreateExecWatchpointExit; } dwError = ERROR_SUCCESS; PAL_CreateExecWatchpointExit: if (NULL != pobjThread) { pobjThread->ReleaseReference(pThread); } if (-1 != fd) { close(fd); } #endif // HAVE_PRWATCH_T LOGEXIT("PAL_CreateExecWatchpoint returns ret:%d\n", dwError); PERF_EXIT(PAL_CreateExecWatchpoint); return dwError; }