/*++ Function: PAL_HasEntered Abstract: This function can be called to determine if the thread has entered the PAL through PAL_Enter or related calls. --*/ BOOL PALAPI PAL_HasEntered() { ENTRY_EXTERNAL("PAL_HasEntered()\n"); CPalThread *pThread = GetCurrentPalThread(); if (pThread == NULL) { ASSERT("PAL_Reenter called on a thread unknown to this PAL\n"); } LOGEXIT("PAL_HasEntered returned\n"); return pThread->IsInPal(); }
HANDLE PALAPI CreateMutexA( IN LPSECURITY_ATTRIBUTES lpMutexAttributes, IN BOOL bInitialOwner, IN LPCSTR lpName) { HANDLE hMutex = NULL; CPalThread *pthr = NULL; PAL_ERROR palError; PERF_ENTRY(CreateMutexA); ENTRY("CreateMutexA(lpMutexAttr=%p, bInitialOwner=%d, lpName=%p (%s)\n", lpMutexAttributes, bInitialOwner, 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 = InternalCreateMutex( pthr, lpMutexAttributes, bInitialOwner, NULL, &hMutex ); } // // 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("CreateMutexA returns HANDLE %p\n", hMutex); PERF_EXIT(CreateMutexA); return hMutex; }
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 == NULL) { ERROR("lpName is NULL\n"); palError = ERROR_INVALID_PARAMETER; goto OpenSemaphoreWExit; } palError = InternalOpenSemaphore( pthr, dwDesiredAccess, bInheritHandle, lpName, &hSemaphore ); OpenSemaphoreWExit: if (NO_ERROR != palError) { pthr->SetLastError(palError); } LOGEXIT("OpenSemaphoreW returns HANDLE %p\n", hSemaphore); PERF_EXIT(OpenSemaphoreW); return hSemaphore; }
/*++ Function: PAL_Reenter Abstract: This function needs to be called on a thread when it enters a region of code that depends on this instance of the PAL in the process, and the current thread is already known to the PAL. NOTE: This function must not modify LastError. --*/ VOID PALAPI PAL_Reenter(PAL_Boundary boundary) { ENTRY_EXTERNAL("PAL_Reenter(boundary=%u)\n", boundary); CPalThread *pThread = GetCurrentPalThread(); if (pThread == NULL) { ASSERT("PAL_Reenter called on a thread unknown to this PAL\n"); } // We ignore the return code. This call should only fail on internal // error, and we assert at the actual failure. pThread->Enter(boundary); LOGEXIT("PAL_Reenter returns\n"); }
PAL_ERROR AllocatePalThread(CPalThread **ppThread) { CPalThread *pThread = NULL; PAL_ERROR palError; #if !HAVE_MACH_EXCEPTIONS // Ensure alternate stack for SIGSEGV handling. Our SIGSEGV handler is set to // run on an alternate stack and the stack needs to be allocated per thread. if (!EnsureSignalAlternateStack()) { ERROR("Cannot allocate alternate stack for SIGSEGV handler!\n"); palError = ERROR_NOT_ENOUGH_MEMORY; goto exit; } #endif // !HAVE_MACH_EXCEPTIONS palError = CreateThreadData(&pThread); if (NO_ERROR != palError) { goto exit; } HANDLE hThread; palError = CreateThreadObject(pThread, pThread, &hThread); if (NO_ERROR != palError) { pthread_setspecific(thObjKey, NULL); pThread->ReleaseThreadReference(); goto exit; } // Like CreateInitialProcessAndThreadObjects, we do not need this // thread handle, since we're not returning it to anyone who will // possibly release it. (void)g_pObjectManager->RevokeHandle(pThread, hThread); PROCAddThread(pThread, pThread); exit: *ppThread = pThread; return palError; }
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: Sleep See MSDN doc. --*/ VOID PALAPI Sleep(IN DWORD dwMilliseconds) { PERF_ENTRY(Sleep); ENTRY("Sleep(dwMilliseconds=%u)\n", dwMilliseconds); CPalThread * pThread = InternalGetCurrentThread(); DWORD internalSleepRet = InternalSleepEx(pThread, dwMilliseconds, FALSE); if (internalSleepRet != 0) { ERROR("Sleep(dwMilliseconds=%u) failed [error=%u]\n", dwMilliseconds, internalSleepRet); pThread->SetLastError(internalSleepRet); } LOGEXIT("Sleep returns VOID\n"); PERF_EXIT(Sleep); }
/*++ Function: CheckPalThread Abstract: This function is called by the ENTRY macro to validate consistency: Whenever a PAL function is called, that thread must have previously registered the fact that it is currently executing code that depends on this PAL by means of PAL_ReverseEnter or PAL_Enter. --*/ extern "C" void CheckPalThread() { if (PALIsInitialized()) { CPalThread *pThread = InternalGetCurrentThread(); if (!pThread) { ASSERT("PAL function called on a thread unknown to this PAL\n"); } else if (!pThread->IsInPal()) { // There are several outstanding issues where we are not maintaining // correct in- vs. out-of-thePAL state. With the advent of // single registration of Mach EH handling per thread, there's no // need to actually be in the PAL any more, and so the following // is being made into a warning, and we'll deprecate the // entire concept later. WARN("PAL function called on a thread external to this PAL\n"); } } }
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; }
HANDLE PALAPI CreateMutexW( IN LPSECURITY_ATTRIBUTES lpMutexAttributes, IN BOOL bInitialOwner, IN LPCWSTR lpName) { HANDLE hMutex = NULL; PAL_ERROR palError; CPalThread *pthr = NULL; PERF_ENTRY(CreateMutexW); ENTRY("CreateMutexW(lpMutexAttr=%p, bInitialOwner=%d, lpName=%p (%S)\n", lpMutexAttributes, bInitialOwner, lpName, lpName?lpName:W16_NULLSTRING); pthr = InternalGetCurrentThread(); palError = InternalCreateMutex( pthr, lpMutexAttributes, bInitialOwner, lpName, &hMutex ); // // 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("CreateMutexW returns HANDLE %p\n", hMutex); PERF_EXIT(CreateMutexW); return hMutex; }
BOOL PALAPI ReleaseMutex( IN HANDLE hMutex ) { PAL_ERROR palError = NO_ERROR; CPalThread *pthr = NULL; PERF_ENTRY(ReleaseMutex); ENTRY("ReleaseMutex(hMutex=%p)\n", hMutex); pthr = InternalGetCurrentThread(); palError = InternalReleaseMutex(pthr, hMutex); if (NO_ERROR != palError) { pthr->SetLastError(palError); } LOGEXIT("ReleaseMutex returns BOOL %d\n", (NO_ERROR == palError)); PERF_EXIT(ReleaseMutex); return (NO_ERROR == palError); }
HANDLE PALAPI OpenMutexA ( IN DWORD dwDesiredAccess, IN BOOL bInheritHandle, IN LPCSTR lpName) { HANDLE hMutex = NULL; CPalThread *pthr = NULL; PAL_ERROR palError; PERF_ENTRY(OpenMutexA); ENTRY("OpenMutexA(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%s))\n", dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:"NULL"); pthr = InternalGetCurrentThread(); /* validate parameters */ if (lpName == nullptr) { ERROR("name is NULL\n"); palError = ERROR_INVALID_PARAMETER; goto OpenMutexAExit; } palError = InternalOpenMutex(pthr, dwDesiredAccess, bInheritHandle, lpName, &hMutex); OpenMutexAExit: if (NO_ERROR != palError) { pthr->SetLastError(palError); } LOGEXIT("OpenMutexA returns HANDLE %p\n", hMutex); PERF_EXIT(OpenMutexA); return hMutex; }
/*++ 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; }
bool CatchHardwareExceptionHolder::IsEnabled() { CPalThread *pThread = InternalGetCurrentThread(); return pThread->IsHardwareExceptionsEnabled(); }
/*++ Function: GetComputerNameW Uses gethostname to get the computer name. See MSDN for functional spec. --*/ PALIMPORT BOOL PALAPI GetComputerNameW( OUT LPWSTR lpBuffer, // address of name buffer IN OUT LPDWORD nSize) // address of size of name buffer { BOOL fRet = FALSE; char szHostName[MAXHOSTNAMELEN+1]; char *pchDot = NULL; DWORD cwchLen = 0; CPalThread *pPalThread = InternalGetCurrentThread(); PERF_ENTRY(GetComputerNameW); ENTRY("GetComputerNameW(lpBuffer = %p, nSize = %p (%d)\n", lpBuffer, nSize, nSize?*nSize:0); if (NULL == lpBuffer || NULL == nSize) { ERROR("lpBuffer == NULL or nSize == NULL"); pPalThread->SetLastError(ERROR_INVALID_PARAMETER); goto done; } if (0 != gethostname(szHostName, sizeof(szHostName)/sizeof(szHostName[0]))) { ERROR("gethostname failed with error (%d) %s\n", errno, strerror(errno)); pPalThread->SetLastError(ERROR_INTERNAL_ERROR); goto done; } // Null terminate the string szHostName[sizeof(szHostName)/sizeof(szHostName[0])-1] = '\0'; // some OSes return the hostname with the domain name included. // We want to return only the host part of the name (see the spec for // more details pchDot = strchr(szHostName, '.'); if (NULL != pchDot) { *pchDot = '\0'; // remove the domain name info } // clip the hostname to MAX_COMPUTERNAME_LENGTH if (sizeof(szHostName) > MAX_COMPUTERNAME_LENGTH) { szHostName[MAX_COMPUTERNAME_LENGTH] = '\0'; } // copy the hostname (including NULL character) cwchLen = MultiByteToWideChar(CP_ACP, 0, szHostName, -1, lpBuffer, *nSize); if (0 == cwchLen) { ERROR ("MultiByteToWideChar failed with error %d when trying to convert the hostname " "%s to wide char\n", pPalThread->GetLastError(), szHostName); if (ERROR_INSUFFICIENT_BUFFER == pPalThread->GetLastError()) { // Find the required size (including NULL) cwchLen = MultiByteToWideChar(CP_ACP, 0, szHostName, -1, NULL, 0); if (0 == cwchLen) { ERROR ("MultiByteToWideChar failed with error %d when trying to find the size of " "%s in wide chars\n", pPalThread->GetLastError(), szHostName); pPalThread->SetLastError(ERROR_INTERNAL_ERROR); } else { // Update the required size *nSize = cwchLen - 1; // don't include the NULL pPalThread->SetLastError(ERROR_BUFFER_OVERFLOW); } } goto done; } *nSize = cwchLen - 1; // don't include the NULL fRet = TRUE; done: LOGEXIT("GetComputerNameW returning BOOL %d\n", fRet); PERF_EXIT(GetComputerNameW); return fRet; }
/*++ Function: GetUserNameW Uses getpwuid_r to get the user name and if it's not available uses getpwuid (with the safety of a critical section). See MSDN for functional spec. --*/ PALIMPORT BOOL PALAPI GetUserNameW( OUT LPWSTR lpBuffer, // address of name buffer IN OUT LPDWORD nSize ) // address of size of name buffer { BOOL fRet = FALSE; struct passwd *pPasswd = NULL; char *szUserName = NULL; DWORD cwchLen = 0; int iEuid = -1; int iRet = -1; CPalThread *pPalThread = InternalGetCurrentThread(); #if HAVE_GETPWUID_R char *pchBuffer = NULL; DWORD dwBufLen = 0; struct passwd sPasswd; #endif // HAVE_GETPWUID_R PERF_ENTRY(GetUserNameW); ENTRY("GetUserNameW(lpBuffer = %p, nSize = %p (%d)\n", lpBuffer, nSize, nSize?*nSize:0); iEuid = geteuid(); if (NULL == lpBuffer || NULL == nSize) { ERROR("lpBuffer == NULL or nSize == NULL"); pPalThread->SetLastError(ERROR_INVALID_PARAMETER); goto done; } #if HAVE_GETPWUID_R dwBufLen = dwInitialPasswdBufferSize; while (NULL == pPasswd) { pchBuffer = (char*) InternalMalloc(pPalThread, sizeof(pchBuffer[0]) * dwBufLen); if (NULL == pchBuffer) { pPalThread->SetLastError(ERROR_OUTOFMEMORY); goto done; } iRet = InternalGetpwuid_r(pPalThread, iEuid, &sPasswd, pchBuffer, dwBufLen, &pPasswd); if (0 != iRet) { WARN("getpwuid_r(%d) returns %d for a buffer size of %d, error string is %s\n", iEuid, iRet, dwBufLen, strerror(iRet)); if (ERANGE == iRet) // need a bigger buffer { InternalFree(pPalThread, pchBuffer); pchBuffer = NULL; pPasswd = NULL; dwBufLen *= 2; // double the buffer continue; // try again } pPalThread->SetLastError(ERROR_INTERNAL_ERROR); goto done; } // Unfortunately, HPUX returns success and result = NULL even when the buffer size is small // (instead of returning ERANGE error). But, since we are using either // sysconf(_SC_GETPW_R_SIZE_MAX) or the HP recommended value of 1024, buffer should always // be big enough for getpwuid_r. if (NULL == pPasswd || NULL == pPasswd->pw_name) { // No matching entry found! something failed somewhere. ERROR("getpwuid_r(%d) returned %p with name NULL!\n", iEuid, pPasswd); pPalThread->SetLastError(ERROR_INTERNAL_ERROR); goto done; } } szUserName = pPasswd->pw_name; #else // HAVE_GETPWUID_R InternalEnterCriticalSection(pPalThread, &identity_critsec); pPasswd = getpwuid(iEuid); if ((NULL == pPasswd) || (NULL == pPasswd->pw_name)) { InternalLeaveCriticalSection(pPalThread, &identity_critsec); ERROR("getpwuid(%d) returned %p with name NULL! error (%d) is %s\n", iEuid, pPasswd, errno, strerror(errno)); pPalThread->SetLastError(ERROR_INTERNAL_ERROR); goto done; } // make a copy so that we can modify it szUserName = InternalStrdup(pPalThread, pPasswd->pw_name); if (NULL == szUserName) { InternalLeaveCriticalSection(pPalThread, &identity_critsec); pPalThread->SetLastError(ERROR_OUTOFMEMORY); goto done; } InternalLeaveCriticalSection(pPalThread, &identity_critsec); #endif // HAVE_GETPWUID_R // truncate the user name if it exceeds the maximum allowed limit if (strlen(szUserName) > UNLEN) { szUserName[UNLEN] = '\0'; } // Copy from pPasswd->pw_name cwchLen = MultiByteToWideChar(CP_ACP, 0, szUserName, -1, lpBuffer, *nSize); if (0 == cwchLen) { ERROR ("MultiByteToWideChar failed with error %d when trying to convert the username " "%s to wide char\n", pPalThread->GetLastError(), szUserName); if (ERROR_INSUFFICIENT_BUFFER == pPalThread->GetLastError()) { // Find the required size (including NULL) cwchLen = MultiByteToWideChar(CP_ACP, 0, szUserName, -1, NULL, 0); if (0 == cwchLen) { ERROR ("MultiByteToWideChar failed with error %d when trying to find the size of " "%s in wide chars\n", pPalThread->GetLastError(), szUserName); pPalThread->SetLastError(ERROR_INTERNAL_ERROR); } else { // Update the required size *nSize = cwchLen; pPalThread->SetLastError(ERROR_MORE_DATA); } } goto done; } *nSize = cwchLen; fRet = TRUE; done: #if HAVE_GETPWUID_R if (NULL != pchBuffer) { InternalFree(pPalThread, pchBuffer); } #else // HAVE_GETPWUID_R if (NULL != szUserName) { InternalFree(pPalThread, szUserName); } #endif // HAVE_GETPWUID_R LOGEXIT("GetUserNameW returning BOOL %d\n", fRet); PERF_EXIT(GetUserNameW); return fRet; }
HANDLE PALAPI CreateSemaphoreA( IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, IN LONG lInitialCount, IN LONG lMaximumCount, IN LPCSTR lpName) { HANDLE hSemaphore = NULL; WCHAR pwName[c_cchMaxSemaphore]; 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 != NULL) { palError = InternalWszNameFromSzName( pthr, lpName, pwName, sizeof(pwName) / sizeof(pwName[0]) ); if (NO_ERROR != palError) { goto CreateSemaphoreAExit; } palError = InternalCreateSemaphore( pthr, lpSemaphoreAttributes, lInitialCount, lMaximumCount, pwName, &hSemaphore ); } else { palError = InternalCreateSemaphore( pthr, lpSemaphoreAttributes, lInitialCount, lMaximumCount, NULL, &hSemaphore ); } CreateSemaphoreAExit: // // 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; }
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; }
/*++ Function: PALCommonCleanup Utility function to free any resource used by the PAL. Parameters : step: selects the desired cleanup step full_cleanup: FALSE: cleanup only what's needed and leave the rest to the OS process cleanup TRUE: full cleanup --*/ void PALCommonCleanup(PALCLEANUP_STEP step, BOOL full_cleanup) { CPalThread *pThread = InternalGetCurrentThread(); static int step_done[PALCLEANUP_STEP_INVALID] = { 0 }; switch (step) { case PALCLEANUP_ALL_STEPS: case PALCLEANUP_STEP_ONE: /* Note: in order to work correctly, this step should be executed with init_count > 0 */ if (!step_done[PALCLEANUP_STEP_ONE]) { step_done[PALCLEANUP_STEP_ONE] = 1; PALSetShutdownIntent(); // // Let the synchronization manager know we're about to shutdown // CPalSynchMgrController::PrepareForShutdown(); #ifdef _DEBUG PROCDumpThreadList(); #endif TRACE("About to suspend every other thread\n"); /* prevent other threads from acquiring signaled objects */ PROCCondemnOtherThreads(); /* prevent other threads from using services we're shutting down */ PROCSuspendOtherThreads(); TRACE("Every other thread suspended until exit\n"); } /* Fall down for PALCLEANUP_ALL_STEPS */ if (PALCLEANUP_ALL_STEPS != step) break; case PALCLEANUP_STEP_TWO: if (!step_done[PALCLEANUP_STEP_TWO]) { step_done[PALCLEANUP_STEP_TWO] = 1; /* LOADFreeeModules needs to be called before unitializing the rest of the PAL since it could result in calling DllMain for loaded libraries. For the user DllMain, all PAL APIs should still be functional. */ LOADFreeModules(FALSE); #ifdef PAL_PERF PERFDisableProcessProfile(); PERFDisableThreadProfile(FALSE); PERFTerminate(); #endif if (full_cleanup) { /* close primary handles of standard file objects */ FILECleanupStdHandles(); /* This unloads the palrt so, during its unloading, they can call any number of APIs, so we have to be active for it to work. */ FMTMSG_FormatMessageCleanUp(); VIRTUALCleanup(); /* SEH requires information from the process structure to work; LOADFreeModules requires SEH to be functional when calling DllMain. Therefore SEHCleanup must go between LOADFreeModules and PROCCleanupInitialProcess */ SEHCleanup(); PROCCleanupInitialProcess(); } // Object manager shutdown may cause all CPalThread objects // to be deleted. Since the CPalThread of the shutdown thread // needs to be available for reference by the thread suspension unsafe // operations, the reference of CPalThread is incremented here // to keep it alive until PAL finishes cleanup. pThread->AddThreadReference(); // // Shutdown object manager -- this needs to happen before the // synch manager shutdown since it will call into the synch // manager to free object synch data // static_cast<CSharedMemoryObjectManager*>(g_pObjectManager)->Shutdown(pThread); // // Final synch manager shutdown // CPalSynchMgrController::Shutdown(pThread, full_cleanup); if (full_cleanup) { /* It needs to be done after stopping the handle manager, because the cleanup will delete the critical section which is used when closing the handle of a file mapping */ MAPCleanup(); // MutexCleanup(); MiscCleanup(); TLSCleanup(); } // The thread object will no longer be available after the shutdown thread // releases the thread reference. g_fThreadDataAvailable = FALSE; pThread->ReleaseThreadReference(); pthread_setspecific(thObjKey, NULL); // Make sure any TLS entry is removed. // Since thread object is no longer available here, // the code path from here should stop using any functions // that reference thread object. SHMCleanup(); TRACE("PAL Terminated.\n"); } break; default: ASSERT("Unknown final cleanup step %d", step); break; } }
void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved) { MODSTRUCT *module = NULL; BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */ CPalThread *pThread; pThread = InternalGetCurrentThread(); if (UserCreatedThread != pThread->GetThreadType()) { return; } /* Validate dwReason */ switch(dwReason) { case DLL_PROCESS_ATTACH: ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n"); break; case DLL_PROCESS_DETACH: ASSERT("got called with DLL_PROCESS_DETACH parameter! Why?\n"); InLoadOrder = FALSE; break; case DLL_THREAD_ATTACH: TRACE("Calling DllMain(DLL_THREAD_ATTACH) on all known modules.\n"); break; case DLL_THREAD_DETACH: TRACE("Calling DllMain(DLL_THREAD_DETACH) on all known modules.\n"); InLoadOrder = FALSE; break; default: ASSERT("LOADCallDllMain called with unknown parameter %d!\n", dwReason); return; } LockModuleList(); module = &exe_module; do { if (!InLoadOrder) module = module->prev; if (module->threadLibCalls) { if (module->pDllMain) { #if !_NO_DEBUG_MESSAGES_ /* reset ENTRY nesting level back to zero while inside the callback... */ int old_level; old_level = DBG_change_entrylevel(0); #endif /* !_NO_DEBUG_MESSAGES_ */ { // This module may be foreign to our PAL, so leave our PAL. // If it depends on us, it will re-enter. PAL_LeaveHolder holder; module->pDllMain(module->hinstance, dwReason, lpReserved); } #if !_NO_DEBUG_MESSAGES_ /* ...and set nesting level back to what it was */ DBG_change_entrylevel(old_level); #endif /* !_NO_DEBUG_MESSAGES_ */ } } if (InLoadOrder) module = module->next; } while (module != &exe_module); UnlockModuleList(); }
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; }
HANDLE PALAPI CreateMutexA ( IN LPSECURITY_ATTRIBUTES lpMutexAttributes, IN BOOL bInitialOwner, IN LPCSTR lpName) { HANDLE hMutex = NULL; WCHAR pwName[c_cchMaxMutex]; CPalThread *pthr = NULL; PAL_ERROR palError; PERF_ENTRY(CreateMutexA); ENTRY("CreateMutexA(lpMutexAttr=%p, bInitialOwner=%d, lpName=%p (%s)\n", lpMutexAttributes, bInitialOwner, lpName, lpName?lpName:"NULL"); pthr = InternalGetCurrentThread(); if (lpName != NULL) { palError = InternalWszNameFromSzName( pthr, lpName, pwName, sizeof(pwName) / sizeof(pwName[0]) ); if (NO_ERROR != palError) { goto CreateMutexAExit; } palError = InternalCreateMutex( pthr, lpMutexAttributes, bInitialOwner, pwName, &hMutex ); } else { palError = InternalCreateMutex( pthr, lpMutexAttributes, bInitialOwner, NULL, &hMutex ); } CreateMutexAExit: // // 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("CreateMutexA returns HANDLE %p\n", hMutex); PERF_EXIT(CreateMutexA); return hMutex; }