1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 Thread object and core APIs
21 #include "pal/dbgmsg.h"
22 SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
24 #include "pal/corunix.hpp"
25 #include "pal/context.h"
26 #include "pal/thread.hpp"
27 #include "pal/mutex.hpp"
28 #include "pal/handlemgr.hpp"
30 #include "pal/seh.hpp"
32 #include "procprivate.hpp"
33 #include "pal/process.h"
34 #include "pal/module.h"
35 #include "pal/environ.h"
38 #if defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID
39 #include <sys/cdefs.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
48 #include <pthread_np.h>
55 #include <mach/mach.h>
56 #endif // HAVE_MACH_THREADS
60 #include "pal/fakepoll.h"
70 // If we don't have sys/lwp.h but do expect to use _lwp_self, declare it to silence compiler warnings
71 #if HAVE__LWP_SELF && !HAVE_SYS_LWP_H && !HAVE_LWP_H
72 extern "C" int _lwp_self ();
75 using namespace CorUnix;
78 /* ------------------- Definitions ------------------------------*/
80 // The default stack size of a newly created thread (currently 256KB)
81 // when the dwStackSize parameter of PAL_CreateThread()
82 // is zero. This value can be set by setting the
83 // environment variable PAL_THREAD_DEFAULT_STACK_SIZE
84 // (the value should be in bytes and in hex).
85 DWORD CPalThread::s_dwDefaultThreadStackSize = 256*1024;
87 /* list of free CPalThread objects */
88 static Volatile<CPalThread*> free_threads_list = NULL;
90 /* lock to access list of free THREAD structures */
91 /* NOTE: can't use a CRITICAL_SECTION here (see comment in FreeTHREAD) */
92 int free_threads_spinlock = 0;
94 /* lock to access iEndingThreads counter, condition variable to signal shutdown
95 thread when any remaining threads have died, and count of exiting threads that
96 can't be suspended. */
97 pthread_mutex_t ptmEndThread;
98 pthread_cond_t ptcEndThread;
99 static int iEndingThreads = 0;
101 // Activation function that gets called when an activation is injected into a thread.
102 PAL_ActivationFunction g_activationFunction = NULL;
103 // Function to check if an activation can be safely injected at a specified context
104 PAL_SafeActivationCheckFunction g_safeActivationCheckFunction = NULL;
107 ThreadCleanupRoutine(
109 IPalObject *pObjectToCleanup,
111 bool fCleanupSharedState
115 ThreadInitializationRoutine(
117 CObjectType *pObjectType,
118 void *pImmutableData,
120 void *pProcessLocalData
124 IncrementEndingThreadCount(
129 DecrementEndingThreadCount(
133 CObjectType CorUnix::otThread(
135 ThreadCleanupRoutine,
136 ThreadInitializationRoutine,
137 0, //sizeof(CThreadImmutableData),
138 sizeof(CThreadProcessLocalData),
139 0, //sizeof(CThreadSharedData),
140 0, // THREAD_ALL_ACCESS,
141 CObjectType::SecuritySupported,
142 CObjectType::SecurityInfoNotPersisted,
143 CObjectType::UnnamedObject,
144 CObjectType::LocalDuplicationOnly,
145 CObjectType::WaitableObject,
146 CObjectType::SingleTransitionObject,
147 CObjectType::ThreadReleaseHasNoSideEffects,
151 CAllowedObjectTypes aotThread(otiThread);
155 InternalEndCurrentThreadWrapper
157 Destructor for the thread-specific data representing the current PAL thread.
158 Called from pthread_exit. (pthread_exit is not called from the thread on which
159 main() was first invoked. This is not a problem, though, since when main()
160 returns, this results in an implicit call to exit().)
164 static void InternalEndCurrentThreadWrapper(void *arg)
166 CPalThread *pThread = (CPalThread *) arg;
168 // When pthread_exit calls us, it has already removed the PAL thread
169 // from TLS. Since InternalEndCurrentThread calls functions that assert
170 // that the current thread is known to this PAL, and that pThread
171 // actually is the current PAL thread, put it back in TLS temporarily.
172 pthread_setspecific(thObjKey, pThread);
173 (void)PAL_Enter(PAL_BoundaryTop);
175 /* Call entry point functions of every attached modules to
176 indicate the thread is exiting */
177 /* note : no need to enter a critical section for serialization, the loader
178 will lock its own critical section */
179 LOADCallDllMain(DLL_THREAD_DETACH, NULL);
181 // PAL_Leave will be called just before we release the thread reference
182 // in InternalEndCurrentThread.
183 InternalEndCurrentThread(pThread);
184 pthread_setspecific(thObjKey, NULL);
191 Initialize the TLS subsystem
195 /* Create the pthread key for thread objects, which we use
196 for fast access to the current thread object. */
197 if (pthread_key_create(&thObjKey, InternalEndCurrentThreadWrapper))
199 ERROR("Couldn't create the thread object key\n");
203 SPINLOCKInit(&free_threads_spinlock);
212 Shutdown the TLS subsystem
216 SPINLOCKDestroy(&free_threads_spinlock);
218 pthread_key_delete(thObjKey);
226 Allocate CPalThread instance
229 The fresh thread structure, NULL otherwise
231 CPalThread* AllocTHREAD()
233 CPalThread* pThread = NULL;
236 SPINLOCKAcquire(&free_threads_spinlock, 0);
238 pThread = free_threads_list;
241 free_threads_list = pThread->GetNext();
244 /* Release the lock */
245 SPINLOCKRelease(&free_threads_spinlock);
249 pThread = InternalNew<CPalThread>();
253 pThread = new (pThread) CPalThread;
264 Free THREAD structure
267 static void FreeTHREAD(CPalThread *pThread)
270 // Run the destructors for this object
273 pThread->~CPalThread();
276 // Fill value so we can find code re-using threads after they're dead. We
277 // check against pThread->dwGuard when getting the current thread's data.
278 memset((void*)pThread, 0xcc, sizeof(*pThread));
281 // We SHOULD be doing the following, but it causes massive problems. See the
283 //pthread_setspecific(thObjKey, NULL); // Make sure any TLS entry is removed.
286 // Never actually free the THREAD structure to make the TLS lookaside cache work.
287 // THREAD* for terminated thread can be stuck in the lookaside cache code for an
288 // arbitrary amount of time. The unused THREAD* structures has to remain in a
289 // valid memory and thus can't be returned to the heap.
291 // TODO: is this really true? Why would the entry remain in the cache for
292 // an indefinite period of time after we've flushed it?
295 /* NOTE: can't use a CRITICAL_SECTION here: EnterCriticalSection(&cs,TRUE) and
296 LeaveCriticalSection(&cs,TRUE) need to access the thread private data
297 stored in the very THREAD structure that we just destroyed. Entering and
298 leaving the critical section with internal==FALSE leads to possible hangs
299 in the PROCSuspendOtherThreads logic, at shutdown time
301 Update: [TODO] PROCSuspendOtherThreads has been removed. Can this
305 SPINLOCKAcquire(&free_threads_spinlock, 0);
307 pThread->SetNext(free_threads_list);
308 free_threads_list = pThread;
310 /* Release the lock */
311 SPINLOCKRelease(&free_threads_spinlock);
317 THREADGetThreadProcessId
319 returns the process owner ID of the indicated hThread
322 THREADGetThreadProcessId(
324 // UNIXTODO Should take pThread parameter here (modify callers)
328 CPalThread *pTargetThread;
329 IPalObject *pobjThread = NULL;
330 PAL_ERROR palError = NO_ERROR;
332 DWORD dwProcessId = 0;
334 pThread = InternalGetCurrentThread();
336 palError = InternalGetThreadDataFromHandle(
344 if (NO_ERROR != palError)
346 if (!pThread->IsDummy())
348 dwProcessId = GetCurrentProcessId();
352 ASSERT("Dummy thread passed to THREADGetProcessId\n");
355 if (NULL != pobjThread)
357 pobjThread->ReleaseReference(pThread);
362 ERROR("Couldn't retreive the hThread:%p pid owner !\n", hThread);
382 PERF_ENTRY(GetCurrentThreadId);
383 ENTRY("GetCurrentThreadId()\n");
386 // TODO: should do perf test to see how this compares
387 // with calling InternalGetCurrentThread (i.e., is our lookaside
388 // cache faster on average than pthread_self?)
391 dwThreadId = (DWORD)THREADSilentGetCurrentThreadId();
393 LOGEXIT("GetCurrentThreadId returns DWORD %#x\n", dwThreadId);
394 PERF_EXIT(GetCurrentThreadId);
409 PAL_GetCurrentThread(
412 PERF_ENTRY(GetCurrentThread);
413 ENTRY("GetCurrentThread()\n");
415 LOGEXIT("GetCurrentThread returns HANDLE %p\n", hPseudoCurrentThread);
416 PERF_EXIT(GetCurrentThread);
418 /* return a pseudo handle */
419 return (HANDLE) hPseudoCurrentThread;
435 PERF_ENTRY(SwitchToThread);
436 ENTRY("SwitchToThread(VOID)\n");
438 /* sched_yield yields to another thread in the current process. This implementation
439 won't work well for cross-process synchronization. */
440 ret = (sched_yield() == 0);
442 LOGEXIT("SwitchToThread returns BOOL %d\n", ret);
443 PERF_EXIT(SwitchToThread);
453 lpThreadAttributes could be ignored.
461 IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
462 IN DWORD dwStackSize,
463 IN LPTHREAD_START_ROUTINE lpStartAddress,
464 IN LPVOID lpParameter,
465 IN DWORD dwCreationFlags,
466 OUT LPDWORD lpThreadId)
470 HANDLE hNewThread = NULL;
472 PERF_ENTRY(CreateThread);
473 ENTRY("CreateThread(lpThreadAttr=%p, dwStackSize=%u, lpStartAddress=%p, "
474 "lpParameter=%p, dwFlags=%#x, lpThreadId=%#x)\n",
475 lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter,
476 dwCreationFlags, lpThreadId);
478 pThread = InternalGetCurrentThread();
480 palError = InternalCreateThread(
492 if (NO_ERROR != palError)
494 pThread->SetLastError(palError);
497 LOGEXIT("CreateThread returns HANDLE %p\n", hNewThread);
498 PERF_EXIT(CreateThread);
504 CorUnix::InternalCreateThread(
506 LPSECURITY_ATTRIBUTES lpThreadAttributes,
508 LPTHREAD_START_ROUTINE lpStartAddress,
510 DWORD dwCreationFlags,
511 PalThreadType eThreadType,
517 CPalThread *pNewThread = NULL;
518 CObjectAttributes oa;
519 bool fAttributesInitialized = FALSE;
520 bool fThreadDataAddedToProcessList = FALSE;
521 HANDLE hNewThread = NULL;
524 pthread_attr_t pthreadAttr;
525 size_t pthreadStackSize;
526 #if PTHREAD_CREATE_MODIFIES_ERRNO
528 #endif // PTHREAD_CREATE_MODIFIES_ERRNO
529 BOOL fHoldingProcessLock = FALSE;
535 // Since the PAL is in the middle of shutting down we don't want to
536 // create any new threads (since it's possible for that new thread
537 // to create another thread before the shutdown thread gets around
538 // to suspending it, and so on). We don't want to return an error
539 // here, though, as some programs (in particular, build) do not
540 // handle CreateThread errors properly -- instead, we just put
541 // the calling thread to sleep (unless it is the shutdown thread,
542 // which could occur if a DllMain PROCESS_DETACH handler tried to
543 // create a new thread for some odd reason).
546 ERROR("process is terminating, can't create new thread.\n");
548 if (pThread->GetThreadId() != static_cast<DWORD>(terminator))
552 poll(NULL, 0, INFTIM);
559 // This is the shutdown thread, so just return an error
562 palError = ERROR_PROCESS_ABORTED;
567 /* Validate parameters */
569 if (lpThreadAttributes != NULL)
571 ASSERT("lpThreadAttributes parameter must be NULL (%p)\n",
573 palError = ERROR_INVALID_PARAMETER;
577 // Ignore the STACK_SIZE_PARAM_IS_A_RESERVATION flag
578 dwCreationFlags &= ~STACK_SIZE_PARAM_IS_A_RESERVATION;
580 if ((dwCreationFlags != 0) && (dwCreationFlags != CREATE_SUSPENDED))
582 ASSERT("dwCreationFlags parameter is invalid (%#x)\n", dwCreationFlags);
583 palError = ERROR_INVALID_PARAMETER;
588 // Create the CPalThread for the thread
591 pNewThread = AllocTHREAD();
592 if (NULL == pNewThread)
594 palError = ERROR_OUTOFMEMORY;
598 palError = pNewThread->RunPreCreateInitializers();
599 if (NO_ERROR != palError)
604 pNewThread->m_lpStartAddress = lpStartAddress;
605 pNewThread->m_lpStartParameter = lpParameter;
606 pNewThread->m_bCreateSuspended = (dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED;
607 pNewThread->m_eThreadType = eThreadType;
609 if (0 != pthread_attr_init(&pthreadAttr))
611 ERROR("couldn't initialize pthread attributes\n");
612 palError = ERROR_INTERNAL_ERROR;
616 fAttributesInitialized = TRUE;
618 /* adjust the stack size if necessary */
619 if (0 != pthread_attr_getstacksize(&pthreadAttr, &pthreadStackSize))
621 ERROR("couldn't set thread stack size\n");
622 palError = ERROR_INTERNAL_ERROR;
626 TRACE("default pthread stack size is %d, caller requested %d (default is %d)\n",
627 pthreadStackSize, dwStackSize, CPalThread::s_dwDefaultThreadStackSize);
629 if (0 == dwStackSize)
631 dwStackSize = CPalThread::s_dwDefaultThreadStackSize;
634 #ifdef PTHREAD_STACK_MIN
635 if (PTHREAD_STACK_MIN > pthreadStackSize)
637 WARN("default stack size is reported as %d, but PTHREAD_STACK_MIN is "
638 "%d\n", pthreadStackSize, PTHREAD_STACK_MIN);
642 if (pthreadStackSize < dwStackSize)
644 TRACE("setting thread stack size to %d\n", dwStackSize);
645 if (0 != pthread_attr_setstacksize(&pthreadAttr, dwStackSize))
647 ERROR("couldn't set pthread stack size to %d\n", dwStackSize);
648 palError = ERROR_INTERNAL_ERROR;
654 TRACE("using the system default thread stack size of %d\n", pthreadStackSize);
657 #if HAVE_THREAD_SELF || HAVE__LWP_SELF
658 /* Create new threads as "bound", so each pthread is permanently bound
659 to an LWP. Get/SetThreadContext() depend on this 1:1 mapping. */
660 pthread_attr_setscope(&pthreadAttr, PTHREAD_SCOPE_SYSTEM);
661 #endif // HAVE_THREAD_SELF || HAVE__LWP_SELF
664 // We never call pthread_join, so create the new thread as detached
667 iError = pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);
668 _ASSERTE(0 == iError);
671 // Create the IPalObject for the thread and store it in the object
674 palError = CreateThreadObject(
679 if (NO_ERROR != palError)
685 // Add the thread to the process list
689 // We use the process lock to ensure that we're not interrupted
690 // during the creation process. After adding the CPalThread reference
691 // to the process list, we want to make sure the actual thread has been
692 // started. Otherwise, there's a window where the thread can be found
693 // in the process list but doesn't yet exist in the system.
697 fHoldingProcessLock = TRUE;
699 PROCAddThread(pThread, pNewThread);
700 fThreadDataAddedToProcessList = TRUE;
703 // Spawn the new pthread
706 #if PTHREAD_CREATE_MODIFIES_ERRNO
708 #endif // PTHREAD_CREATE_MODIFIES_ERRNO
710 #ifdef FEATURE_PAL_SXS
711 _ASSERT_MSG(pNewThread->IsInPal(), "New threads we're about to spawn should always be in the PAL.\n");
712 #endif // FEATURE_PAL_SXS
713 iError = pthread_create(&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread);
715 #if PTHREAD_CREATE_MODIFIES_ERRNO
718 // Restore errno if pthread_create succeeded.
721 #endif // PTHREAD_CREATE_MODIFIES_ERRNO
725 ERROR("pthread_create failed, error is %d (%s)\n", iError, strerror(iError));
726 palError = ERROR_NOT_ENOUGH_MEMORY;
731 // Wait for the new thread to finish its initial startup tasks
732 // (i.e., the ones that might fail)
734 if (pNewThread->WaitForStartStatus())
737 // Everything succeeded. Store the handle for the new thread and
738 // the thread's ID in the out params
740 *phThread = hNewThread;
742 if (NULL != lpThreadId)
744 *lpThreadId = pNewThread->GetThreadId();
749 ERROR("error occurred in THREADEntry, thread creation failed.\n");
750 palError = ERROR_INTERNAL_ERROR;
755 // If we're here, then we've locked the process list and both pthread_create
756 // and WaitForStartStatus succeeded. Thus, we can now unlock the process list.
757 // Since palError == NO_ERROR, we won't call this again in the exit block.
760 fHoldingProcessLock = FALSE;
764 if (fAttributesInitialized)
766 if (0 != pthread_attr_destroy(&pthreadAttr))
768 WARN("pthread_attr_destroy() failed\n");
772 if (NO_ERROR != palError)
775 // We either were not able to create the new thread, or a failure
776 // occurred in the new thread's entry routine. Free up the associated
780 if (fThreadDataAddedToProcessList)
782 PROCRemoveThread(pThread, pNewThread);
785 // Once we remove the thread from the process list, we can call
786 // PROCProcessUnlock.
788 if (fHoldingProcessLock)
792 fHoldingProcessLock = FALSE;
795 _ASSERT_MSG(!fHoldingProcessLock, "Exiting InternalCreateThread while still holding the process critical section.\n");
816 ENTRY("ExitThread(dwExitCode=%u)\n", dwExitCode);
817 PERF_ENTRY_ONLY(ExitThread);
819 pThread = InternalGetCurrentThread();
821 /* store the exit code */
822 pThread->SetExitCode(dwExitCode);
824 /* pthread_exit runs TLS destructors and cleanup routines,
825 possibly registered by foreign code. The right thing
826 to do here is to leave the PAL. Our own TLS destructor
827 re-enters us explicitly. */
828 PAL_Leave(PAL_BoundaryTop);
830 /* kill the thread (itself), resulting in a call to InternalEndCurrentThread */
833 ASSERT("pthread_exit should not return!\n");
847 IN LPDWORD lpExitCode)
849 PAL_ERROR palError = NO_ERROR;
850 CPalThread *pthrCurrent = NULL;
851 CPalThread *pthrTarget = NULL;
852 IPalObject *pobjThread = NULL;
855 PERF_ENTRY(GetExitCodeThread);
856 ENTRY("GetExitCodeThread(hThread = %p, lpExitCode = %p)\n",
857 hThread, lpExitCode);
859 if (NULL == lpExitCode)
861 WARN("Got NULL lpExitCode\n");
862 palError = ERROR_INVALID_PARAMETER;
866 pthrCurrent = InternalGetCurrentThread();
867 palError = InternalGetThreadDataFromHandle(
875 pthrTarget->Lock(pthrCurrent);
877 fExitCodeSet = pthrTarget->GetExitCode(lpExitCode);
880 if (TS_DONE == pthrTarget->synchronizationInfo.GetThreadState())
882 #ifdef FEATURE_PAL_SXS
883 // The thread exited without ever calling ExitThread.
884 // It must have wandered in.
886 #else // FEATURE_PAL_SXS
887 ASSERT("exit code not set but thread is dead\n");
888 #endif // FEATURE_PAL_SXS
892 *lpExitCode = STILL_ACTIVE;
896 pthrTarget->Unlock(pthrCurrent);
899 if (NULL != pobjThread)
901 pobjThread->ReleaseReference(pthrCurrent);
904 LOGEXIT("GetExitCodeThread returns BOOL %d\n", NO_ERROR == palError);
905 PERF_EXIT(GetExitCodeThread);
907 return NO_ERROR == palError;
913 InternalEndCurrentThread
915 Does any necessary memory clean up, signals waiting threads, and then forces
916 the current thread to exit.
920 CorUnix::InternalEndCurrentThread(
924 PAL_ERROR palError = NO_ERROR;
925 ISynchStateController *pSynchStateController = NULL;
928 PERFDisableThreadProfile(UserCreatedThread != pThread->GetThreadType());
932 // Abandon any objects owned by this thread
935 palError = g_pSynchronizationManager->AbandonObjectsOwnedByThread(
940 if (NO_ERROR != palError)
942 ERROR("Failure abandoning owned objects");
946 // Need to synchronize setting the thread state to TS_DONE since
947 // this is checked for in InternalSuspendThreadFromData.
948 // TODO: Is this still needed after removing InternalSuspendThreadFromData?
951 pThread->suspensionInfo.AcquireSuspensionLock(pThread);
952 IncrementEndingThreadCount();
953 pThread->synchronizationInfo.SetThreadState(TS_DONE);
954 pThread->suspensionInfo.ReleaseSuspensionLock(pThread);
957 // Mark the thread object as signaled
960 palError = pThread->GetThreadObject()->GetSynchStateController(
962 &pSynchStateController
965 if (NO_ERROR == palError)
967 palError = pSynchStateController->SetSignalCount(1);
968 if (NO_ERROR != palError)
970 ASSERT("Unable to mark thread object as signaled");
973 pSynchStateController->ReleaseController();
977 ASSERT("Unable to obtain state controller for thread");
980 #ifndef FEATURE_PAL_SXS
981 // If this is the last thread then delete the process' data,
982 // but don't exit because the application hosting the PAL
983 // might have its own threads.
984 if (PROCGetNumberOfThreads() == 1)
986 TRACE("Last thread is exiting\n");
987 DecrementEndingThreadCount();
988 TerminateCurrentProcessNoExit(FALSE);
991 #endif // !FEATURE_PAL_SXS
993 /* Do this ONLY if we aren't the last thread -> otherwise
994 it gets done by TerminateProcess->
995 PROCCleanupProcess->PALShutdown->PAL_Terminate */
998 // Add a reference to the thread data before releasing the
999 // thread object, so we can still use it
1002 pThread->AddThreadReference();
1005 // Release the reference to the IPalObject for this thread
1008 pThread->GetThreadObject()->ReleaseReference(pThread);
1010 /* Remove thread for the thread list of the process
1011 (don't do if this is the last thread -> gets handled by
1012 TerminateProcess->PROCCleanupProcess->PROCTerminateOtherThreads) */
1014 PROCRemoveThread(pThread, pThread);
1016 #ifdef FEATURE_PAL_SXS
1017 // Ensure that EH is disabled on the current thread
1018 SEHDisable(pThread);
1019 PAL_Leave(PAL_BoundaryTop);
1020 #endif // FEATURE_PAL_SXS
1024 // Now release our reference to the thread data. We cannot touch
1025 // it after this point
1028 pThread->ReleaseThreadReference();
1029 DecrementEndingThreadCount();
1045 CPalThread *pThread;
1047 int iPriority = THREAD_PRIORITY_ERROR_RETURN;
1049 PERF_ENTRY(GetThreadPriority);
1050 ENTRY("GetThreadPriority(hThread=%p)\n", hThread);
1052 pThread = InternalGetCurrentThread();
1054 palError = InternalGetThreadPriority(
1060 if (NO_ERROR != palError)
1062 pThread->SetLastError(palError);
1065 LOGEXIT("GetThreadPriorityExit returns int %d\n", iPriority);
1066 PERF_EXIT(GetThreadPriority);
1072 CorUnix::InternalGetThreadPriority(
1073 CPalThread *pThread,
1078 PAL_ERROR palError = NO_ERROR;
1079 CPalThread *pTargetThread;
1080 IPalObject *pobjThread = NULL;
1082 palError = InternalGetThreadDataFromHandle(
1085 0, // THREAD_QUERY_INFORMATION
1090 if (NO_ERROR != palError)
1092 goto InternalGetThreadPriorityExit;
1095 pTargetThread->Lock(pThread);
1097 *piPriority = pTargetThread->GetThreadPriority();
1099 pTargetThread->Unlock(pThread);
1101 InternalGetThreadPriorityExit:
1103 if (NULL != pobjThread)
1105 pobjThread->ReleaseReference(pThread);
1124 CPalThread *pThread;
1125 PAL_ERROR palError = NO_ERROR;
1127 PERF_ENTRY(SetThreadPriority);
1128 ENTRY("SetThreadPriority(hThread=%p, nPriority=%#x)\n", hThread, nPriority);
1130 pThread = InternalGetCurrentThread();
1132 palError = InternalSetThreadPriority(
1138 if (NO_ERROR != palError)
1140 pThread->SetLastError(palError);
1143 LOGEXIT("SetThreadPriority returns BOOL %d\n", NO_ERROR == palError);
1144 PERF_EXIT(SetThreadPriority);
1146 return NO_ERROR == palError;
1150 CorUnix::InternalSetThreadPriority(
1151 CPalThread *pThread,
1152 HANDLE hTargetThread,
1156 PAL_ERROR palError = NO_ERROR;
1157 CPalThread *pTargetThread = NULL;
1158 IPalObject *pobjThread = NULL;
1161 struct sched_param schedParam;
1164 float posix_priority;
1167 palError = InternalGetThreadDataFromHandle(
1170 0, // THREAD_SET_INFORMATION
1175 if (NO_ERROR != palError)
1177 goto InternalSetThreadPriorityExit;
1180 pTargetThread->Lock(pThread);
1182 /* validate the requested priority */
1183 switch (iNewPriority)
1185 case THREAD_PRIORITY_TIME_CRITICAL: /* fall through */
1186 case THREAD_PRIORITY_IDLE:
1189 case THREAD_PRIORITY_HIGHEST: /* fall through */
1190 case THREAD_PRIORITY_ABOVE_NORMAL: /* fall through */
1191 case THREAD_PRIORITY_NORMAL: /* fall through */
1192 case THREAD_PRIORITY_BELOW_NORMAL: /* fall through */
1193 case THREAD_PRIORITY_LOWEST:
1194 #if PAL_IGNORE_NORMAL_THREAD_PRIORITY
1195 /* We aren't going to set the thread priority. Just record what it is,
1197 pTargetThread->m_iThreadPriority = iNewPriority;
1198 goto InternalSetThreadPriorityExit;
1203 ASSERT("Priority %d not supported\n", iNewPriority);
1204 palError = ERROR_INVALID_PARAMETER;
1205 goto InternalSetThreadPriorityExit;
1208 /* check if the thread is still running */
1209 if (TS_DONE == pTargetThread->synchronizationInfo.GetThreadState())
1211 /* the thread has exited, set the priority in the thread structure
1213 pTargetThread->m_iThreadPriority = iNewPriority;
1214 goto InternalSetThreadPriorityExit;
1217 /* get the previous thread schedule parameters. We need to know the
1218 scheduling policy to determine the priority range */
1219 if (pthread_getschedparam(
1220 pTargetThread->GetPThreadSelf(),
1225 ASSERT("Unable to get current thread scheduling information\n");
1226 palError = ERROR_INTERNAL_ERROR;
1227 goto InternalSetThreadPriorityExit;
1230 #if !HAVE_SCHED_OTHER_ASSIGNABLE
1231 /* Defining thread priority for SCHED_OTHER is implementation defined.
1232 Some platforms like NetBSD cannot reassign it as they are dynamic.
1234 if (policy == SCHED_OTHER)
1236 TRACE("Pthread priority levels for SCHED_OTHER cannot be reassigned on this platform\n");
1237 goto InternalSetThreadPriorityExit;
1241 #if HAVE_SCHED_GET_PRIORITY
1242 max_priority = sched_get_priority_max(policy);
1243 min_priority = sched_get_priority_min(policy);
1244 if( -1 == max_priority || -1 == min_priority)
1246 ASSERT("sched_get_priority_min/max failed; error is %d (%s)\n",
1247 errno, strerror(errno));
1248 palError = ERROR_INTERNAL_ERROR;
1249 goto InternalSetThreadPriorityExit;
1252 max_priority = PAL_THREAD_PRIORITY_MAX;
1253 min_priority = PAL_THREAD_PRIORITY_MIN;
1256 TRACE("Pthread priorities for policy %d must be in the range %d to %d\n",
1257 policy, min_priority, max_priority);
1259 /* explanation for fancy maths below :
1260 POSIX doesn't specify the range of thread priorities that can be used
1261 with pthread_setschedparam. Instead, one must use sched_get_priority_min
1262 and sched_get_priority_max to obtain the lower and upper bounds of this
1263 range. Since the PAL also uses a range of values (from Idle [-15] to
1264 Time Critical [+15]), we have to do a mapping from a known range to an
1265 unknown (at compilation) range.
1267 -substracting the minimal PAL priority from the desired priority. this
1268 gives a value between 0 and the PAL priority range
1269 -dividing this value by the PAL priority range. this allows us to
1270 express the desired priority as a floating-point value between 0 and 1
1271 -multiplying this value by the PTHREAD priority range. This gives a
1272 value between 0 and the PTHREAD priority range
1273 -adding the minimal PTHREAD priority range. This will give us a value
1274 between the minimal and maximla pthread priority, which should be
1275 equivalent to the original PAL value.
1277 example : suppose a pthread range 100 to 200, and a desired priority
1278 of 0 (halfway between PAL minimum and maximum)
1279 0 - (IDLE [-15]) = 15
1280 15 / (TIMECRITICAL[15] - IDLE[-15]) = 0.5
1281 0.5 * (pthreadmax[200]-pthreadmin[100]) = 50
1282 50 + pthreadmin[100] = 150 -> halfway between pthread min and max
1284 posix_priority = (iNewPriority - THREAD_PRIORITY_IDLE);
1285 posix_priority /= (THREAD_PRIORITY_TIME_CRITICAL - THREAD_PRIORITY_IDLE);
1286 posix_priority *= (max_priority-min_priority);
1287 posix_priority += min_priority;
1289 schedParam.sched_priority = (int)posix_priority;
1291 TRACE("PAL priority %d is mapped to pthread priority %d\n",
1292 iNewPriority, schedParam.sched_priority);
1294 /* Finally, set the new priority into place */
1295 if (pthread_setschedparam(
1296 pTargetThread->GetPThreadSelf(),
1301 #if SET_SCHEDPARAM_NEEDS_PRIVS
1304 // UNIXTODO: Should log a warning to the event log
1305 TRACE("Caller does not have OS privileges to call pthread_setschedparam\n");
1306 pTargetThread->m_iThreadPriority = iNewPriority;
1307 goto InternalSetThreadPriorityExit;
1311 ASSERT("Unable to set thread priority (errno %d)\n", errno);
1312 palError = ERROR_INTERNAL_ERROR;
1313 goto InternalSetThreadPriorityExit;
1316 pTargetThread->m_iThreadPriority = iNewPriority;
1318 InternalSetThreadPriorityExit:
1320 if (NULL != pTargetThread)
1322 pTargetThread->Unlock(pThread);
1325 if (NULL != pobjThread)
1327 pobjThread->ReleaseReference(pThread);
1334 CorUnix::GetThreadTimesInternal(
1336 OUT LPFILETIME lpKernelTime,
1337 OUT LPFILETIME lpUserTime)
1340 BOOL retval = FALSE;
1341 const __int64 SECS_TO_NS = 1000000000; /* 10^9 */
1342 const __int64 USECS_TO_NS = 1000; /* 10^3 */
1344 #if HAVE_MACH_THREADS
1345 thread_basic_info resUsage;
1346 PAL_ERROR palError = NO_ERROR;
1347 CPalThread *pthrCurrent = NULL;
1348 CPalThread *pthrTarget = NULL;
1349 IPalObject *pobjThread = NULL;
1350 mach_msg_type_number_t resUsage_count = THREAD_BASIC_INFO_COUNT;
1352 pthrCurrent = InternalGetCurrentThread();
1353 palError = InternalGetThreadDataFromHandle(
1361 if (palError != NO_ERROR)
1363 ASSERT("Unable to get thread data from handle %p"
1364 "thread\n", hThread);
1365 SetLastError(ERROR_INTERNAL_ERROR);
1366 goto SetTimesToZero;
1369 pthrTarget->Lock(pthrCurrent);
1371 mach_port_t mhThread;
1372 mhThread = pthread_mach_thread_np(pthrTarget->GetPThreadSelf());
1374 kern_return_t status;
1375 status = thread_info(
1378 (thread_info_t)&resUsage,
1381 pthrTarget->Unlock(pthrCurrent);
1383 if (status != KERN_SUCCESS)
1385 ASSERT("Unable to get resource usage information for the current "
1387 SetLastError(ERROR_INTERNAL_ERROR);
1388 goto SetTimesToZero;
1391 /* Get the time of user mode execution, in nanoseconds */
1392 calcTime = (__int64)resUsage.user_time.seconds * SECS_TO_NS;
1393 calcTime += (__int64)resUsage.user_time.microseconds * USECS_TO_NS;
1394 /* Assign the time into lpUserTime */
1395 lpUserTime->dwLowDateTime = (DWORD)calcTime;
1396 lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1398 /* Get the time of kernel mode execution, in nanoseconds */
1399 calcTime = (__int64)resUsage.system_time.seconds * SECS_TO_NS;
1400 calcTime += (__int64)resUsage.system_time.microseconds * USECS_TO_NS;
1401 /* Assign the time into lpKernelTime */
1402 lpKernelTime->dwLowDateTime = (DWORD)calcTime;
1403 lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1407 goto GetThreadTimesInternalExit;
1409 #elif defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID /* Currently unimplemented */
1412 CPalThread *pThread;
1413 CPalThread *pTargetThread;
1414 IPalObject *pobjThread = NULL;
1417 struct kinfo_lwp *klwp;
1421 pThread = InternalGetCurrentThread();
1423 palError = InternalGetThreadDataFromHandle(
1426 0, // THREAD_GET_CONTEXT
1430 if (palError != NO_ERROR)
1432 ASSERT("Unable to get thread data from handle %p"
1433 "thread\n", hThread);
1434 SetLastError(ERROR_INTERNAL_ERROR);
1435 goto SetTimesToZero;
1438 kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
1441 ASSERT("kvm_open(3) error");
1442 SetLastError(ERROR_INTERNAL_ERROR);
1443 goto SetTimesToZero;
1446 pTargetThread->Lock(pThread);
1448 klwp = kvm_getlwps(kd, getpid(), 0, sizeof(struct kinfo_lwp), &nlwps);
1449 if (klwp == NULL || nlwps < 1)
1452 ASSERT("Unable to get clock from %p thread\n", hThread);
1453 SetLastError(ERROR_INTERNAL_ERROR);
1454 pTargetThread->Unlock(pThread);
1455 goto SetTimesToZero;
1458 for (i = 0; i < nlwps; i++)
1460 if (klwp[i].l_lid == THREADSilentGetCurrentThreadId())
1470 ASSERT("Unable to get clock from %p thread\n", hThread);
1471 SetLastError(ERROR_INTERNAL_ERROR);
1472 pTargetThread->Unlock(pThread);
1473 goto SetTimesToZero;
1476 pTargetThread->Unlock(pThread);
1480 calcTime = (__int64) klwp[i].l_rtime_sec * SECS_TO_NS;
1481 calcTime += (__int64) klwp[i].l_rtime_usec * USECS_TO_NS;
1482 lpUserTime->dwLowDateTime = (DWORD)calcTime;
1483 lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1485 /* NetBSD as of (7.0) doesn't differentiate used time in user/kernel for lwp */
1486 lpKernelTime->dwLowDateTime = 0;
1487 lpKernelTime->dwHighDateTime = 0;
1490 goto GetThreadTimesInternalExit;
1492 #else //HAVE_MACH_THREADS
1495 CPalThread *pThread;
1496 CPalThread *pTargetThread;
1497 IPalObject *pobjThread = NULL;
1500 pThread = InternalGetCurrentThread();
1502 palError = InternalGetThreadDataFromHandle(
1505 0, // THREAD_GET_CONTEXT
1509 if (palError != NO_ERROR)
1511 ASSERT("Unable to get thread data from handle %p"
1512 "thread\n", hThread);
1513 SetLastError(ERROR_INTERNAL_ERROR);
1514 goto SetTimesToZero;
1517 pTargetThread->Lock(pThread);
1519 #if HAVE_PTHREAD_GETCPUCLOCKID
1520 if (pthread_getcpuclockid(pTargetThread->GetPThreadSelf(), &cid) != 0)
1523 ASSERT("Unable to get clock from thread\n", hThread);
1524 SetLastError(ERROR_INTERNAL_ERROR);
1525 pTargetThread->Unlock(pThread);
1526 goto SetTimesToZero;
1530 if (clock_gettime(cid, &ts) != 0)
1532 ASSERT("clock_gettime() failed; errno is %d (%s)\n", errno, strerror(errno));
1533 SetLastError(ERROR_INTERNAL_ERROR);
1534 pTargetThread->Unlock(pThread);
1535 goto SetTimesToZero;
1538 pTargetThread->Unlock(pThread);
1540 /* Calculate time in nanoseconds and assign to user time */
1541 calcTime = (__int64) ts.tv_sec * SECS_TO_NS;
1542 calcTime += (__int64) ts.tv_nsec;
1543 lpUserTime->dwLowDateTime = (DWORD)calcTime;
1544 lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1546 /* Set kernel time to zero, for now */
1547 lpKernelTime->dwLowDateTime = 0;
1548 lpKernelTime->dwHighDateTime = 0;
1551 goto GetThreadTimesInternalExit;
1553 #endif //HAVE_MACH_THREADS
1557 lpUserTime->dwLowDateTime = 0;
1558 lpUserTime->dwHighDateTime = 0;
1559 lpKernelTime->dwLowDateTime = 0;
1560 lpKernelTime->dwHighDateTime = 0;
1561 goto GetThreadTimesInternalExit;
1563 GetThreadTimesInternalExit:
1577 OUT LPFILETIME lpCreationTime,
1578 OUT LPFILETIME lpExitTime,
1579 OUT LPFILETIME lpKernelTime,
1580 OUT LPFILETIME lpUserTime)
1582 PERF_ENTRY(GetThreadTimes);
1583 ENTRY("GetThreadTimes(hThread=%p, lpExitTime=%p, lpKernelTime=%p,"
1585 hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime );
1587 FILETIME KernelTime, UserTime;
1589 BOOL retval = GetThreadTimesInternal(hThread, &KernelTime, &UserTime);
1591 /* Not sure if this still needs to be here */
1593 TRACE ("thread_info User: %ld sec,%ld microsec. Kernel: %ld sec,%ld"
1595 resUsage.user_time.seconds, resUsage.user_time.microseconds,
1596 resUsage.system_time.seconds, resUsage.system_time.microseconds);
1602 /* Produce the time in 100s of ns */
1603 calcTime = ((ULONG64)UserTime.dwHighDateTime << 32);
1604 calcTime += (ULONG64)UserTime.dwLowDateTime;
1606 lpUserTime->dwLowDateTime = (DWORD)calcTime;
1607 lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1611 /* Produce the time in 100s of ns */
1612 calcTime = ((ULONG64)KernelTime.dwHighDateTime << 32);
1613 calcTime += (ULONG64)KernelTime.dwLowDateTime;
1615 lpKernelTime->dwLowDateTime = (DWORD)calcTime;
1616 lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1618 //Set CreationTime and Exit time to zero for now - maybe change this later?
1621 lpCreationTime->dwLowDateTime = 0;
1622 lpCreationTime->dwHighDateTime = 0;
1627 lpExitTime->dwLowDateTime = 0;
1628 lpExitTime->dwHighDateTime = 0;
1631 LOGEXIT("GetThreadTimes returns BOOL %d\n", retval);
1632 PERF_EXIT(GetThreadTimes);
1639 CPalThread::ThreadEntry(
1644 CPalThread *pThread;
1645 PTHREAD_START_ROUTINE pfnStartRoutine;
1649 pThread = reinterpret_cast<CPalThread*>(pvParam);
1651 if (NULL == pThread)
1653 ASSERT("THREAD pointer is NULL!\n");
1657 #if defined(FEATURE_PAL_SXS) && defined(_DEBUG)
1658 // We cannot assert yet, as we haven't set in this thread into the TLS, and so __ASSERT_ENTER
1659 // will fail if the assert fails and we'll crash.
1660 //_ASSERT_MSG(pThread->m_fInPal == 1, "New threads should always be in the PAL upon ThreadEntry.\n");
1661 if (g_Dbg_asserts_enabled && pThread->m_fInPal != 1)
1663 #endif // FEATURE_PAL_SXS && _DEBUG
1665 pThread->m_threadId = THREADSilentGetCurrentThreadId();
1666 pThread->m_pthreadSelf = pthread_self();
1667 #if HAVE_MACH_THREADS
1668 pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf);
1670 #if HAVE_THREAD_SELF
1671 pThread->m_dwLwpId = (DWORD) thread_self();
1672 #elif HAVE__LWP_SELF
1673 pThread->m_dwLwpId = (DWORD) _lwp_self();
1675 pThread->m_dwLwpId = 0;
1678 palError = pThread->RunPostCreateInitializers();
1679 if (NO_ERROR != palError)
1681 ASSERT("Error %i initializing thread data (post creation)\n", palError);
1685 // Check if the thread should be started suspended.
1686 if (pThread->GetCreateSuspended())
1688 palError = pThread->suspensionInfo.InternalSuspendNewThreadFromData(pThread);
1689 if (NO_ERROR != palError)
1691 ASSERT("Error %i attempting to suspend new thread\n", palError);
1696 // We need to run any APCs that have already been queued for
1700 (void) g_pSynchronizationManager->DispatchPendingAPCs(pThread);
1705 // All startup operations that might have failed have succeeded,
1706 // so thread creation is successful. Let CreateThread return.
1709 pThread->SetStartStatus(TRUE);
1712 pThread->synchronizationInfo.SetThreadState(TS_RUNNING);
1714 if (UserCreatedThread == pThread->GetThreadType())
1716 /* Inform all loaded modules that a thread has been created */
1717 /* note : no need to take a critical section to serialize here; the loader
1718 will take the module critical section */
1719 LOADCallDllMain(DLL_THREAD_ATTACH, NULL);
1723 PERFAllocThreadInfo();
1724 PERFEnableThreadProfile(UserCreatedThread != pThread->GetThreadType());
1727 /* call the startup routine */
1728 pfnStartRoutine = pThread->GetStartAddress();
1729 pvPar = pThread->GetStartParameter();
1731 retValue = (*pfnStartRoutine)(pvPar);
1733 TRACE("Thread exited (%u)\n", retValue);
1734 ExitThread(retValue);
1736 /* Note: never get here */
1737 ASSERT("ExitThread failed!\n");
1743 // Notify InternalCreateThread that a failure occurred
1746 if (NULL != pThread)
1748 pThread->synchronizationInfo.SetThreadState(TS_FAILED);
1749 pThread->SetStartStatus(FALSE);
1752 /* do not call ExitThread : we don't want to call DllMain(), and the thread
1753 isn't in a clean state (e.g. lpThread isn't in TLS). the cleanup work
1754 above should release all resources */
1759 #define PAL_THREAD_DEFAULT_STACK_SIZE "PAL_THREAD_DEFAULT_STACK_SIZE"
1762 CorUnix::InitializeGlobalThreadData(
1766 PAL_ERROR palError = NO_ERROR;
1767 char *pszStackSize = NULL;
1770 // Read in the environment to see whether we need to change the default
1771 // thread stack size.
1773 pszStackSize = EnvironGetenv(PAL_THREAD_DEFAULT_STACK_SIZE);
1774 if (NULL != pszStackSize)
1776 // Environment variable exists
1778 DWORD dw = PAL_strtoul(pszStackSize, &pszEnd, 16); // treat it as hex
1779 if ( (pszStackSize != pszEnd) && (0 != dw) )
1781 CPalThread::s_dwDefaultThreadStackSize = dw;
1796 Create the CPalThread for the startup thread
1797 or another external thread entering the PAL
1801 ppThread - on success, receives the CPalThread
1808 CorUnix::CreateThreadData(
1809 CPalThread **ppThread
1812 PAL_ERROR palError = NO_ERROR;
1813 CPalThread *pThread = NULL;
1815 /* Create the thread object */
1816 pThread = AllocTHREAD();
1818 if (NULL == pThread)
1820 palError = ERROR_OUTOFMEMORY;
1821 goto CreateThreadDataExit;
1824 palError = pThread->RunPreCreateInitializers();
1826 if (NO_ERROR != palError)
1828 goto CreateThreadDataExit;
1831 pThread->SetLastError(0);
1833 pThread->m_threadId = THREADSilentGetCurrentThreadId();
1834 pThread->m_pthreadSelf = pthread_self();
1835 #if HAVE_MACH_THREADS
1836 pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf);
1838 #if HAVE_THREAD_SELF
1839 pThread->m_dwLwpId = (DWORD) thread_self();
1840 #elif HAVE__LWP_SELF
1841 pThread->m_dwLwpId = (DWORD) _lwp_self();
1843 pThread->m_dwLwpId = 0;
1846 palError = pThread->RunPostCreateInitializers();
1847 if (NO_ERROR != palError)
1849 goto CreateThreadDataExit;
1852 *ppThread = pThread;
1854 CreateThreadDataExit:
1856 if (NO_ERROR != palError)
1858 if (NULL != pThread)
1860 pThread->ReleaseThreadReference();
1872 Creates the IPalObject for a thread, storing
1873 the reference in the CPalThread
1876 pThread - the thread data for the creating thread
1877 pNewThread - the thread data for the thread being initialized
1884 CorUnix::CreateThreadObject(
1885 CPalThread *pThread,
1886 CPalThread *pNewThread,
1890 PAL_ERROR palError = NO_ERROR;
1891 IPalObject *pobjThread = NULL;
1892 IDataLock *pDataLock;
1893 HANDLE hThread = NULL;
1894 CThreadProcessLocalData *pLocalData = NULL;
1895 CObjectAttributes oa;
1896 BOOL fThreadDataStoredInObject = FALSE;
1897 IPalObject *pobjRegisteredThread = NULL;
1900 // Create the IPalObject for the thread
1903 palError = g_pObjectManager->AllocateObject(
1910 if (NO_ERROR != palError)
1912 goto CreateThreadObjectExit;
1916 // Store the CPalThread inside of the IPalObject
1919 palError = pobjThread->GetProcessLocalData(
1923 reinterpret_cast<void **>(&pLocalData)
1926 if (NO_ERROR != palError)
1928 goto CreateThreadObjectExit;
1931 pLocalData->pThread = pNewThread;
1932 pDataLock->ReleaseLock(pThread, TRUE);
1933 fThreadDataStoredInObject = TRUE;
1936 // Register the IPalObject (obtaining a handle)
1939 palError = g_pObjectManager->RegisterObject(
1943 0, //THREAD_ALL_ACCESS,
1945 &pobjRegisteredThread
1949 // pobjThread is invalidated by the call to RegisterObject, so NULL
1950 // it out here to prevent it from being released
1955 if (NO_ERROR != palError)
1957 goto CreateThreadObjectExit;
1961 // Store the registered object inside of the thread object,
1962 // adding a reference for the thread itself
1965 pNewThread->m_pThreadObject = pobjRegisteredThread;
1966 pNewThread->m_pThreadObject->AddReference();
1968 *phThread = hThread;
1970 CreateThreadObjectExit:
1972 if (NO_ERROR != palError)
1974 if (NULL != hThread)
1976 g_pObjectManager->RevokeHandle(pThread, hThread);
1979 if (NULL != pNewThread->m_pThreadObject)
1982 // Release the new thread's reference on the underlying thread
1986 pNewThread->m_pThreadObject->ReleaseReference(pThread);
1989 if (!fThreadDataStoredInObject)
1992 // The CPalThread for the new thread was never stored in
1993 // an IPalObject instance, so we need to release the initial
1994 // reference here. (If it has been stored it will get freed in
1995 // the owning object's cleanup routine)
1998 pNewThread->ReleaseThreadReference();
2002 if (NULL != pobjThread)
2004 pobjThread->ReleaseReference(pThread);
2007 if (NULL != pobjRegisteredThread)
2009 pobjRegisteredThread->ReleaseReference(pThread);
2016 CorUnix::InternalCreateDummyThread(
2017 CPalThread *pThread,
2018 LPSECURITY_ATTRIBUTES lpThreadAttributes,
2019 CPalThread **ppDummyThread,
2023 PAL_ERROR palError = NO_ERROR;
2024 CPalThread *pDummyThread = NULL;
2025 IPalObject *pobjThread = NULL;
2026 IPalObject *pobjThreadRegistered = NULL;
2027 IDataLock *pDataLock;
2028 CThreadProcessLocalData *pLocalData;
2029 CObjectAttributes oa(NULL, lpThreadAttributes);
2030 bool fThreadDataStoredInObject = FALSE;
2032 pDummyThread = AllocTHREAD();
2033 if (NULL == pDummyThread)
2035 palError = ERROR_OUTOFMEMORY;
2036 goto InternalCreateDummyThreadExit;
2039 pDummyThread->m_fIsDummy = TRUE;
2041 palError = g_pObjectManager->AllocateObject(
2048 if (NO_ERROR != palError)
2050 goto InternalCreateDummyThreadExit;
2053 palError = pobjThread->GetProcessLocalData(
2057 reinterpret_cast<void **>(&pLocalData)
2060 if (NO_ERROR != palError)
2062 goto InternalCreateDummyThreadExit;
2065 pLocalData->pThread = pDummyThread;
2066 pDataLock->ReleaseLock(pThread, TRUE);
2067 fThreadDataStoredInObject = TRUE;
2069 palError = g_pObjectManager->RegisterObject(
2073 0, // THREAD_ALL_ACCESS
2075 &pobjThreadRegistered
2079 // pobjThread is invalidated by the above call, so NULL
2085 if (NO_ERROR != palError)
2087 goto InternalCreateDummyThreadExit;
2091 // Note the we do NOT store the registered object for the
2092 // thread w/in pDummyThread. Since this thread is not actually
2093 // executing that reference would never be released (and thus
2094 // the thread object would never be cleaned up...)
2097 *ppDummyThread = pDummyThread;
2099 InternalCreateDummyThreadExit:
2101 if (NULL != pobjThreadRegistered)
2103 pobjThreadRegistered->ReleaseReference(pThread);
2106 if (NULL != pobjThread)
2108 pobjThread->ReleaseReference(pThread);
2111 if (NO_ERROR != palError
2112 && NULL != pDummyThread
2113 && !fThreadDataStoredInObject)
2115 pDummyThread->ReleaseThreadReference();
2122 CorUnix::InternalGetThreadDataFromHandle(
2123 CPalThread *pThread,
2125 DWORD dwRightsRequired,
2126 CPalThread **ppTargetThread,
2127 IPalObject **ppobjThread
2130 PAL_ERROR palError = NO_ERROR;
2133 CThreadProcessLocalData *pData;
2135 *ppobjThread = NULL;
2137 if (hPseudoCurrentThread == hThread)
2139 *ppTargetThread = pThread;
2143 palError = g_pObjectManager->ReferenceObjectByHandle(
2151 if (NO_ERROR == palError)
2153 palError = pobj->GetProcessLocalData(
2157 reinterpret_cast<void**>(&pData)
2160 if (NO_ERROR == palError)
2162 *ppTargetThread = pData->pThread;
2163 pLock->ReleaseLock(pThread, FALSE);
2166 // Transfer object reference to out param
2169 *ppobjThread = pobj;
2173 pobj->ReleaseReference(pThread);
2182 CPalThread::RunPreCreateInitializers(
2186 PAL_ERROR palError = NO_ERROR;
2190 // First, perform initialization of CPalThread private members
2193 InternalInitializeCriticalSection(&m_csLock);
2194 m_fLockInitialized = TRUE;
2196 iError = pthread_mutex_init(&m_startMutex, NULL);
2199 goto RunPreCreateInitializersExit;
2202 iError = pthread_cond_init(&m_startCond, NULL);
2205 pthread_mutex_destroy(&m_startMutex);
2206 goto RunPreCreateInitializersExit;
2209 m_fStartItemsInitialized = TRUE;
2212 // Call the pre-create initializers for embedded classes
2215 palError = synchronizationInfo.InitializePreCreate();
2216 if (NO_ERROR != palError)
2218 goto RunPreCreateInitializersExit;
2221 palError = suspensionInfo.InitializePreCreate();
2222 if (NO_ERROR != palError)
2224 goto RunPreCreateInitializersExit;
2227 palError = sehInfo.InitializePreCreate();
2228 if (NO_ERROR != palError)
2230 goto RunPreCreateInitializersExit;
2233 palError = tlsInfo.InitializePreCreate();
2234 if (NO_ERROR != palError)
2236 goto RunPreCreateInitializersExit;
2239 palError = apcInfo.InitializePreCreate();
2240 if (NO_ERROR != palError)
2242 goto RunPreCreateInitializersExit;
2245 palError = crtInfo.InitializePreCreate();
2246 if (NO_ERROR != palError)
2248 goto RunPreCreateInitializersExit;
2251 RunPreCreateInitializersExit:
2256 CPalThread::~CPalThread()
2258 // @UNIXTODO: This is our last chance to unlink our Mach exception handler from the pseudo-chain we're trying
2259 // to maintain. Unfortunately we don't have enough data or control to do this at all well (and we can't
2260 // guarantee that another component hasn't chained to us, about which we can do nothing). If the kernel or
2261 // another component forwards an exception notification to us for this thread things will go badly (we'll
2262 // terminate the process when trying to look up this CPalThread in order to find forwarding information).
2263 // On the flip side I don't believe we'll get here currently unless the thread has been terminated (in
2264 // which case it's not an issue). If we start supporting unload or early disposal of CPalThread objects
2265 // (say when we return from an outer reverse p/invoke) then we'll need to revisit this. But hopefully by
2266 // then we'll have an alternative design for handling hardware exceptions.
2268 if (m_fLockInitialized)
2270 InternalDeleteCriticalSection(&m_csLock);
2273 if (m_fStartItemsInitialized)
2277 iError = pthread_cond_destroy(&m_startCond);
2278 _ASSERTE(0 == iError);
2280 iError = pthread_mutex_destroy(&m_startMutex);
2281 _ASSERTE(0 == iError);
2286 CPalThread::AddThreadReference(
2290 InterlockedIncrement(&m_lRefCount);
2294 CPalThread::ReleaseThreadReference(
2298 LONG lRefCount = InterlockedDecrement(&m_lRefCount);
2299 _ASSERT_MSG(lRefCount >= 0, "Released a thread and ended with a negative refcount (%ld)\n", lRefCount);
2308 CPalThread::RunPostCreateInitializers(
2312 PAL_ERROR palError = NO_ERROR;
2315 // Call the post-create initializers for embedded classes
2318 palError = synchronizationInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2319 if (NO_ERROR != palError)
2321 goto RunPostCreateInitializersExit;
2324 palError = suspensionInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2325 if (NO_ERROR != palError)
2327 goto RunPostCreateInitializersExit;
2330 palError = sehInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2331 if (NO_ERROR != palError)
2333 goto RunPostCreateInitializersExit;
2336 palError = tlsInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2337 if (NO_ERROR != palError)
2339 goto RunPostCreateInitializersExit;
2342 palError = apcInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2343 if (NO_ERROR != palError)
2345 goto RunPostCreateInitializersExit;
2348 palError = crtInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2349 if (NO_ERROR != palError)
2351 goto RunPostCreateInitializersExit;
2354 #ifdef FEATURE_PAL_SXS
2356 palError = SEHEnable(this);
2357 if (NO_ERROR != palError)
2359 goto RunPostCreateInitializersExit;
2361 #endif // FEATURE_PAL_SXS
2363 RunPostCreateInitializersExit:
2369 CPalThread::SetStartStatus(
2370 bool fStartSucceeded
2376 if (m_fStartStatusSet)
2378 ASSERT("Multiple calls to CPalThread::SetStartStatus\n");
2383 // This routine may get called from CPalThread::ThreadEntry
2385 // If we've reached this point there are no further thread
2386 // suspensions that happen at creation time, so reset
2387 // m_bCreateSuspended
2390 m_bCreateSuspended = FALSE;
2392 iError = pthread_mutex_lock(&m_startMutex);
2395 ASSERT("pthread primitive failure\n");
2399 m_fStartStatus = fStartSucceeded;
2400 m_fStartStatusSet = TRUE;
2402 iError = pthread_cond_signal(&m_startCond);
2405 ASSERT("pthread primitive failure\n");
2409 iError = pthread_mutex_unlock(&m_startMutex);
2412 ASSERT("pthread primitive failure\n");
2418 CPalThread::WaitForStartStatus(
2424 iError = pthread_mutex_lock(&m_startMutex);
2427 ASSERT("pthread primitive failure\n");
2431 while (!m_fStartStatusSet)
2433 iError = pthread_cond_wait(&m_startCond, &m_startMutex);
2436 ASSERT("pthread primitive failure\n");
2441 iError = pthread_mutex_unlock(&m_startMutex);
2444 ASSERT("pthread primitive failure\n");
2448 return m_fStartStatus;
2451 /* IncrementEndingThreadCount and DecrementEndingThreadCount are used
2452 to control a global counter that indicates if any threads are about to die.
2453 Once a thread's state is set to TS_DONE, it cannot be suspended. However,
2454 the dying thread can still access PAL resources, which is dangerous if the
2455 thread dies during PAL cleanup. To avoid this, the shutdown thread calls
2456 WaitForEndingThreads after suspending all other threads. WaitForEndingThreads
2457 uses a condition variable along with the global counter to wait for remaining
2458 PAL threads to die before proceeding with cleanup. As threads die, they
2459 decrement the counter and signal the condition variable. */
2462 IncrementEndingThreadCount(
2468 iError = pthread_mutex_lock(&ptmEndThread);
2469 _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2473 iError = pthread_mutex_unlock(&ptmEndThread);
2474 _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2478 DecrementEndingThreadCount(
2484 iError = pthread_mutex_lock(&ptmEndThread);
2485 _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2488 _ASSERTE(iEndingThreads >= 0);
2490 if (iEndingThreads == 0)
2492 iError = pthread_cond_signal(&ptcEndThread);
2493 _ASSERT_MSG(iError == 0, "pthread_cond_signal returned %d\n", iError);
2496 iError = pthread_mutex_unlock(&ptmEndThread);
2497 _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2501 WaitForEndingThreads(
2507 iError = pthread_mutex_lock(&ptmEndThread);
2508 _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2510 while (iEndingThreads > 0)
2512 iError = pthread_cond_wait(&ptcEndThread, &ptmEndThread);
2513 _ASSERT_MSG(iError == 0, "pthread_cond_wait returned %d\n", iError);
2516 iError = pthread_mutex_unlock(&ptmEndThread);
2517 _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2521 CorUnix::InitializeEndingThreadsData(
2525 PAL_ERROR palError = ERROR_INTERNAL_ERROR;
2528 iError = pthread_mutex_init(&ptmEndThread, NULL);
2531 goto InitializeEndingThreadsDataExit;
2534 iError = pthread_cond_init(&ptcEndThread, NULL);
2538 // Don't bother checking the return value of pthread_mutex_destroy
2539 // since PAL initialization will now fail.
2542 pthread_mutex_destroy(&ptmEndThread);
2543 goto InitializeEndingThreadsDataExit;
2546 palError = NO_ERROR;
2548 InitializeEndingThreadsDataExit:
2554 ThreadCleanupRoutine(
2555 CPalThread *pThread,
2556 IPalObject *pObjectToCleanup,
2558 bool fCleanupSharedState
2561 CThreadProcessLocalData *pThreadData = NULL;
2562 CPalThread *pThreadToCleanup = NULL;
2563 IDataLock *pDataLock = NULL;
2564 PAL_ERROR palError = NO_ERROR;
2567 // Free the CPalThread data for the passed in thread
2570 palError = pObjectToCleanup->GetProcessLocalData(
2574 reinterpret_cast<void**>(&pThreadData)
2577 if (NO_ERROR == palError)
2580 // Note that we may be cleaning up the data for the calling
2581 // thread (i.e., pThread == pThreadToCleanup), so the release
2582 // of the thread reference needs to be the last thing that
2583 // we do (though in that case it's very likely that the person
2584 // calling us will be holding an extra reference to allow
2585 // for the thread data to be available while the rest of the
2586 // object cleanup takes place).
2589 pThreadToCleanup = pThreadData->pThread;
2590 pThreadData->pThread = NULL;
2591 pDataLock->ReleaseLock(pThread, TRUE);
2592 pThreadToCleanup->ReleaseThreadReference();
2596 ASSERT("Unable to obtain thread data");
2602 ThreadInitializationRoutine(
2603 CPalThread *pThread,
2604 CObjectType *pObjectType,
2605 void *pImmutableData,
2607 void *pProcessLocalData
2613 // Get base address of the current thread's stack
2615 CPalThread::GetStackBase()
2618 #ifdef _TARGET_MAC64
2619 // This is a Mac specific method
2620 stackBase = pthread_get_stackaddr_np(pthread_self());
2622 pthread_attr_t attr;
2627 pthread_t thread = pthread_self();
2629 status = pthread_attr_init(&attr);
2630 _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
2632 #if HAVE_PTHREAD_ATTR_GET_NP
2633 status = pthread_attr_get_np(thread, &attr);
2634 #elif HAVE_PTHREAD_GETATTR_NP
2635 status = pthread_getattr_np(thread, &attr);
2637 #error Dont know how to get thread attributes on this platform!
2639 _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
2641 status = pthread_attr_getstack(&attr, &stackAddr, &stackSize);
2642 _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
2644 status = pthread_attr_destroy(&attr);
2645 _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
2647 stackBase = (void*)((size_t)stackAddr + stackSize);
2653 // Get limit address of the current thread's stack
2655 CPalThread::GetStackLimit()
2658 #ifdef _TARGET_MAC64
2659 // This is a Mac specific method
2660 stackLimit = ((BYTE *)pthread_get_stackaddr_np(pthread_self()) -
2661 pthread_get_stacksize_np(pthread_self()));
2663 pthread_attr_t attr;
2667 pthread_t thread = pthread_self();
2669 status = pthread_attr_init(&attr);
2670 _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
2672 #if HAVE_PTHREAD_ATTR_GET_NP
2673 status = pthread_attr_get_np(thread, &attr);
2674 #elif HAVE_PTHREAD_GETATTR_NP
2675 status = pthread_getattr_np(thread, &attr);
2677 #error Dont know how to get thread attributes on this platform!
2679 _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
2681 status = pthread_attr_getstack(&attr, &stackLimit, &stackSize);
2682 _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
2684 status = pthread_attr_destroy(&attr);
2685 _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
2691 // Get cached base address of this thread's stack
2692 // Can be called only for the current thread.
2694 CPalThread::GetCachedStackBase()
2696 _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetStackBase called from foreign thread");
2698 if (m_stackBase == NULL)
2700 m_stackBase = GetStackBase();
2706 // Get cached limit address of this thread's stack.
2707 // Can be called only for the current thread.
2709 CPalThread::GetCachedStackLimit()
2711 _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetCachedStackLimit called from foreign thread");
2713 if (m_stackLimit == NULL)
2715 m_stackLimit = GetStackLimit();
2718 return m_stackLimit;
2725 CPalThread* thread = InternalGetCurrentThread();
2726 return thread->GetCachedStackBase();
2733 CPalThread* thread = InternalGetCurrentThread();
2734 return thread->GetCachedStackLimit();
2737 PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread);
2741 PAL_SetActivationFunction
2743 Register an activation function that gets called when an activation is injected
2747 pActivationFunction - activation function
2748 pSafeActivationCheckFunction - function to check if an activation can be safely
2749 injected at a specified context
2756 PAL_SetActivationFunction(
2757 IN PAL_ActivationFunction pActivationFunction,
2758 IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction)
2760 g_activationFunction = pActivationFunction;
2761 g_safeActivationCheckFunction = pSafeActivationCheckFunction;
2766 PAL_InjectActivation
2768 Interrupt the specified thread and have it call an activation function registered
2769 using the PAL_SetActivationFunction
2772 hThread - handle of the target thread
2775 TRUE if it succeeded, FALSE otherwise.
2779 PAL_InjectActivation(
2782 PERF_ENTRY(PAL_InjectActivation);
2783 ENTRY("PAL_InjectActivation(hThread=%p)\n", hThread);
2785 CPalThread *pCurrentThread;
2786 CPalThread *pTargetThread;
2787 IPalObject *pobjThread = NULL;
2789 pCurrentThread = InternalGetCurrentThread();
2791 PAL_ERROR palError = InternalGetThreadDataFromHandle(
2799 if (palError == NO_ERROR)
2801 palError = InjectActivationInternal(pTargetThread);
2804 if (palError == NO_ERROR)
2806 pCurrentThread->SetLastError(palError);
2809 if (pobjThread != NULL)
2811 pobjThread->ReleaseReference(pCurrentThread);
2814 BOOL success = (palError == NO_ERROR);
2815 LOGEXIT("PAL_InjectActivation returns:d\n", success);
2816 PERF_EXIT(PAL_InjectActivation);
2821 #if HAVE_MACH_EXCEPTIONS
2823 extern mach_port_t s_ExceptionPort;
2825 // Get handler details for a given type of exception. If successful the structure pointed at by pHandler is
2826 // filled in and true is returned. Otherwise false is returned.
2827 bool CorUnix::CThreadMachExceptionHandlers::GetHandler(exception_type_t eException, CorUnix::MachExceptionHandler *pHandler)
2829 exception_mask_t bmExceptionMask = (1 << eException);
2830 int idxHandler = GetIndexOfHandler(bmExceptionMask);
2832 // Did we find a handler?
2833 if (idxHandler == -1)
2836 // Found one, so initialize the output structure with the details.
2837 pHandler->m_mask = m_masks[idxHandler];
2838 pHandler->m_handler = m_handlers[idxHandler];
2839 pHandler->m_behavior = m_behaviors[idxHandler];
2840 pHandler->m_flavor = m_flavors[idxHandler];
2845 // Look for a handler for the given exception within the given handler node. Return its index if successful or
2847 int CorUnix::CThreadMachExceptionHandlers::GetIndexOfHandler(exception_mask_t bmExceptionMask)
2849 // Check all handler entries for one handling the exception mask.
2850 for (mach_msg_type_number_t i = 0; i < m_nPorts; i++)
2852 // Entry covers this exception type and the handler isn't null
2853 if (m_masks[i] & bmExceptionMask && m_handlers[i] != MACH_PORT_NULL)
2855 _ASSERTE(m_handlers[i] != s_ExceptionPort);
2857 // One more check; has the target handler port become dead?
2858 mach_port_type_t ePortType;
2859 if (mach_port_type(mach_task_self(), m_handlers[i], &ePortType) == KERN_SUCCESS && !(ePortType & MACH_PORT_TYPE_DEAD_NAME))
2861 // Got a matching entry.
2867 // Didn't find a handler.
2871 #endif // HAVE_MACH_EXCEPTIONS