Merge pull request #6521 from adityamandaleeka/remove_internal_free
[platform/upstream/coreclr.git] / src / pal / src / thread / thread.cpp
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.
4
5 /*++
6
7
8
9 Module Name:
10
11     thread.cpp
12
13 Abstract:
14
15     Thread object and core APIs
16
17
18
19 --*/
20
21 #include "pal/dbgmsg.h"
22 SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
23
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"
29 #include "pal/cs.hpp"
30 #include "pal/seh.hpp"
31
32 #include "procprivate.hpp"
33 #include "pal/process.h"
34 #include "pal/module.h"
35 #include "pal/environ.h"
36 #include "pal/init.h"
37
38 #if defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID
39 #include <sys/cdefs.h>
40 #include <sys/param.h>
41 #include <sys/sysctl.h>
42 #include <kvm.h>
43 #endif
44
45 #include <signal.h>
46 #include <pthread.h>
47 #if HAVE_PTHREAD_NP_H
48 #include <pthread_np.h>
49 #endif
50 #include <unistd.h>
51 #include <errno.h>
52 #include <stddef.h>
53 #include <sys/stat.h>
54 #if HAVE_MACH_THREADS
55 #include <mach/mach.h>
56 #endif // HAVE_MACH_THREADS
57 #if HAVE_POLL
58 #include <poll.h>
59 #else
60 #include "pal/fakepoll.h"
61 #endif  // HAVE_POLL
62 #include <limits.h>
63
64 #if HAVE_SYS_LWP_H
65 #include <sys/lwp.h>
66 #endif
67 #if HAVE_LWP_H
68 #include <lwp.h>
69 #endif
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 ();
73 #endif
74
75 using namespace CorUnix;
76
77
78 /* ------------------- Definitions ------------------------------*/
79
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; 
86
87 /* list of free CPalThread objects */
88 static Volatile<CPalThread*> free_threads_list = NULL;
89
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;
93
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;
100
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;
105
106 void
107 ThreadCleanupRoutine(
108     CPalThread *pThread,
109     IPalObject *pObjectToCleanup,
110     bool fShutdown,
111     bool fCleanupSharedState
112     );
113
114 PAL_ERROR
115 ThreadInitializationRoutine(
116     CPalThread *pThread,
117     CObjectType *pObjectType,
118     void *pImmutableData,
119     void *pSharedData,
120     void *pProcessLocalData
121     );
122
123 void 
124 IncrementEndingThreadCount(
125     void
126     );
127
128 void 
129 DecrementEndingThreadCount(
130     void
131     );
132
133 CObjectType CorUnix::otThread(
134                 otiThread,
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,
148                 CObjectType::NoOwner
149                 );
150
151 CAllowedObjectTypes aotThread(otiThread);
152
153 /*++
154 Function:
155   InternalEndCurrentThreadWrapper
156
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().)
161
162   arg: the PAL thread
163 */
164 static void InternalEndCurrentThreadWrapper(void *arg)
165 {
166     CPalThread *pThread = (CPalThread *) arg;
167
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);
174     
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);
180
181     // PAL_Leave will be called just before we release the thread reference
182     // in InternalEndCurrentThread.
183     InternalEndCurrentThread(pThread);
184     pthread_setspecific(thObjKey, NULL);
185 }
186
187 /*++
188 Function:
189   TLSInitialize
190
191   Initialize the TLS subsystem
192 --*/
193 BOOL TLSInitialize()
194 {
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))
198     {
199         ERROR("Couldn't create the thread object key\n");
200         return FALSE;
201     }
202
203     SPINLOCKInit(&free_threads_spinlock);
204
205     return TRUE;
206 }
207
208 /*++
209 Function:
210     TLSCleanup
211
212     Shutdown the TLS subsystem
213 --*/
214 VOID TLSCleanup()
215 {
216     SPINLOCKDestroy(&free_threads_spinlock);
217
218     pthread_key_delete(thObjKey);
219 }
220
221 /*++
222 Function:
223     AllocTHREAD
224
225 Abstract:
226     Allocate CPalThread instance
227   
228 Return:
229     The fresh thread structure, NULL otherwise
230 --*/
231 CPalThread* AllocTHREAD()
232 {
233     CPalThread* pThread = NULL;
234
235     /* Get the lock */
236     SPINLOCKAcquire(&free_threads_spinlock, 0);
237
238     pThread = free_threads_list;
239     if (pThread != NULL)
240     {
241         free_threads_list = pThread->GetNext();
242     }
243
244     /* Release the lock */
245     SPINLOCKRelease(&free_threads_spinlock);
246
247     if (pThread == NULL)
248     {
249         pThread = InternalNew<CPalThread>();
250     }
251     else
252     {
253         pThread = new (pThread) CPalThread;
254     }
255
256     return pThread;
257 }
258
259 /*++
260 Function:
261     FreeTHREAD
262
263 Abstract:
264     Free THREAD structure
265   
266 --*/
267 static void FreeTHREAD(CPalThread *pThread)
268 {
269     //
270     // Run the destructors for this object
271     //
272
273     pThread->~CPalThread();
274
275 #ifdef _DEBUG
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));
279 #endif
280     
281     // We SHOULD be doing the following, but it causes massive problems. See the 
282     // comment below.
283     //pthread_setspecific(thObjKey, NULL); // Make sure any TLS entry is removed.
284
285     //
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.
290     //
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?
293     //
294
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 
300
301        Update: [TODO] PROCSuspendOtherThreads has been removed. Can this 
302        code be changed?*/
303
304     /* Get the lock */
305     SPINLOCKAcquire(&free_threads_spinlock, 0);
306
307     pThread->SetNext(free_threads_list);
308     free_threads_list = pThread;
309
310     /* Release the lock */
311     SPINLOCKRelease(&free_threads_spinlock);
312 }
313
314
315 /*++
316 Function:
317   THREADGetThreadProcessId
318
319 returns the process owner ID of the indicated hThread
320 --*/
321 DWORD 
322 THREADGetThreadProcessId(
323     HANDLE hThread
324     // UNIXTODO Should take pThread parameter here (modify callers)
325     )
326 {
327     CPalThread *pThread;
328     CPalThread *pTargetThread;
329     IPalObject *pobjThread = NULL;
330     PAL_ERROR palError = NO_ERROR;
331     
332     DWORD dwProcessId = 0;
333
334     pThread = InternalGetCurrentThread();
335
336     palError = InternalGetThreadDataFromHandle(
337         pThread,
338         hThread,
339         0,
340         &pTargetThread,
341         &pobjThread
342         );
343
344     if (NO_ERROR != palError)
345     {
346         if (!pThread->IsDummy())
347         {
348             dwProcessId = GetCurrentProcessId();
349         }
350         else
351         {
352             ASSERT("Dummy thread passed to THREADGetProcessId\n");
353         }
354
355         if (NULL != pobjThread)
356         {
357             pobjThread->ReleaseReference(pThread);
358         }
359     }
360     else
361     {
362         ERROR("Couldn't retreive the hThread:%p pid owner !\n", hThread);
363     }
364
365     
366     return dwProcessId;
367 }
368
369 /*++
370 Function:
371   GetCurrentThreadId
372
373 See MSDN doc.
374 --*/
375 DWORD
376 PALAPI
377 GetCurrentThreadId(
378             VOID)
379 {
380     DWORD dwThreadId;
381
382     PERF_ENTRY(GetCurrentThreadId);
383     ENTRY("GetCurrentThreadId()\n");
384
385     //
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?)
389     //
390     
391     dwThreadId = (DWORD)THREADSilentGetCurrentThreadId();
392     
393     LOGEXIT("GetCurrentThreadId returns DWORD %#x\n", dwThreadId);    
394     PERF_EXIT(GetCurrentThreadId);
395     
396     return dwThreadId;
397 }
398
399
400
401 /*++
402 Function:
403   GetCurrentThread
404
405 See MSDN doc.
406 --*/
407 HANDLE
408 PALAPI
409 PAL_GetCurrentThread(
410           VOID)
411 {
412     PERF_ENTRY(GetCurrentThread);
413     ENTRY("GetCurrentThread()\n");
414     
415     LOGEXIT("GetCurrentThread returns HANDLE %p\n", hPseudoCurrentThread);
416     PERF_EXIT(GetCurrentThread);
417
418     /* return a pseudo handle */
419     return (HANDLE) hPseudoCurrentThread;
420 }
421
422 /*++
423 Function:
424   SwitchToThread
425
426 See MSDN doc.
427 --*/
428 BOOL
429 PALAPI
430 SwitchToThread(
431     VOID)
432 {
433     BOOL ret;
434
435     PERF_ENTRY(SwitchToThread);
436     ENTRY("SwitchToThread(VOID)\n");
437
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);
441
442     LOGEXIT("SwitchToThread returns BOOL %d\n", ret);
443     PERF_EXIT(SwitchToThread);
444
445     return ret;
446 }
447
448 /*++
449 Function:
450   CreateThread
451
452 Note:
453   lpThreadAttributes could be ignored.
454
455 See MSDN doc.
456
457 --*/
458 HANDLE
459 PALAPI
460 CreateThread(
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)
467 {
468     PAL_ERROR palError;
469     CPalThread *pThread;
470     HANDLE hNewThread = NULL;
471     
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);
477
478     pThread = InternalGetCurrentThread();
479
480     palError = InternalCreateThread(
481         pThread,
482         lpThreadAttributes,
483         dwStackSize,
484         lpStartAddress,
485         lpParameter,
486         dwCreationFlags,
487         UserCreatedThread,
488         lpThreadId,
489         &hNewThread
490         );
491
492     if (NO_ERROR != palError)
493     {
494         pThread->SetLastError(palError);
495     }    
496
497     LOGEXIT("CreateThread returns HANDLE %p\n", hNewThread);
498     PERF_EXIT(CreateThread);
499
500     return hNewThread;
501 }
502
503 PAL_ERROR
504 CorUnix::InternalCreateThread(
505     CPalThread *pThread,
506     LPSECURITY_ATTRIBUTES lpThreadAttributes,
507     DWORD dwStackSize,
508     LPTHREAD_START_ROUTINE lpStartAddress,
509     LPVOID lpParameter,
510     DWORD dwCreationFlags,
511     PalThreadType eThreadType,
512     LPDWORD lpThreadId,
513     HANDLE *phThread
514     )
515 {
516     PAL_ERROR palError;
517     CPalThread *pNewThread = NULL;
518     CObjectAttributes oa;
519     bool fAttributesInitialized = FALSE;
520     bool fThreadDataAddedToProcessList = FALSE;
521     HANDLE hNewThread = NULL;
522     
523     pthread_t pthread;
524     pthread_attr_t pthreadAttr;
525     size_t pthreadStackSize;
526 #if PTHREAD_CREATE_MODIFIES_ERRNO
527     int storedErrno;
528 #endif  // PTHREAD_CREATE_MODIFIES_ERRNO
529     BOOL fHoldingProcessLock = FALSE;
530     int iError = 0;
531
532     if (0 != terminator)
533     {
534         //
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).
544         //
545         
546         ERROR("process is terminating, can't create new thread.\n");
547
548         if (pThread->GetThreadId() != static_cast<DWORD>(terminator))
549         {
550             while (true)
551             {
552                 poll(NULL, 0, INFTIM);
553                 sched_yield();
554             }
555         }
556         else
557         {
558             //
559             // This is the shutdown thread, so just return an error
560             //
561             
562             palError = ERROR_PROCESS_ABORTED;
563             goto EXIT;
564         }
565     }
566
567     /* Validate parameters */
568
569     if (lpThreadAttributes != NULL)
570     {
571         ASSERT("lpThreadAttributes parameter must be NULL (%p)\n", 
572                lpThreadAttributes);
573         palError = ERROR_INVALID_PARAMETER;
574         goto EXIT;
575     }
576     
577     // Ignore the STACK_SIZE_PARAM_IS_A_RESERVATION flag
578     dwCreationFlags &= ~STACK_SIZE_PARAM_IS_A_RESERVATION;
579     
580     if ((dwCreationFlags != 0) && (dwCreationFlags != CREATE_SUSPENDED))
581     {
582         ASSERT("dwCreationFlags parameter is invalid (%#x)\n", dwCreationFlags);
583         palError = ERROR_INVALID_PARAMETER;
584         goto EXIT;
585     }
586
587     //
588     // Create the CPalThread for the thread
589     //
590
591     pNewThread = AllocTHREAD();
592     if (NULL == pNewThread)
593     {
594         palError = ERROR_OUTOFMEMORY;
595         goto EXIT;
596     }
597
598     palError = pNewThread->RunPreCreateInitializers();
599     if (NO_ERROR != palError)
600     {
601         goto EXIT;
602     }
603
604     pNewThread->m_lpStartAddress = lpStartAddress;
605     pNewThread->m_lpStartParameter = lpParameter;
606     pNewThread->m_bCreateSuspended = (dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED;
607     pNewThread->m_eThreadType = eThreadType;
608
609     if (0 != pthread_attr_init(&pthreadAttr))
610     {
611         ERROR("couldn't initialize pthread attributes\n");
612         palError = ERROR_INTERNAL_ERROR;
613         goto EXIT;        
614     }
615
616     fAttributesInitialized = TRUE;
617
618     /* adjust the stack size if necessary */
619     if (0 != pthread_attr_getstacksize(&pthreadAttr, &pthreadStackSize))
620     {
621         ERROR("couldn't set thread stack size\n");
622         palError = ERROR_INTERNAL_ERROR;
623         goto EXIT;        
624     }
625
626     TRACE("default pthread stack size is %d, caller requested %d (default is %d)\n",
627           pthreadStackSize, dwStackSize, CPalThread::s_dwDefaultThreadStackSize);
628
629     if (0 == dwStackSize)
630     {
631         dwStackSize = CPalThread::s_dwDefaultThreadStackSize;
632     }
633
634 #ifdef PTHREAD_STACK_MIN
635     if (PTHREAD_STACK_MIN > pthreadStackSize)
636     {
637         WARN("default stack size is reported as %d, but PTHREAD_STACK_MIN is "
638              "%d\n", pthreadStackSize, PTHREAD_STACK_MIN);
639     }
640 #endif
641     
642     if (pthreadStackSize < dwStackSize)
643     {
644         TRACE("setting thread stack size to %d\n", dwStackSize);
645         if (0 != pthread_attr_setstacksize(&pthreadAttr, dwStackSize))
646         {
647             ERROR("couldn't set pthread stack size to %d\n", dwStackSize);
648             palError = ERROR_INTERNAL_ERROR;
649             goto EXIT;
650         }
651     }
652     else
653     {
654         TRACE("using the system default thread stack size of %d\n", pthreadStackSize);
655     }
656
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
662
663     //
664     // We never call pthread_join, so create the new thread as detached
665     //
666
667     iError = pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);
668     _ASSERTE(0 == iError);
669
670     //
671     // Create the IPalObject for the thread and store it in the object
672     //
673
674     palError = CreateThreadObject(
675         pThread,
676         pNewThread,
677         &hNewThread);
678
679     if (NO_ERROR != palError)
680     {
681         goto EXIT;
682     }
683
684     //
685     // Add the thread to the process list
686     //
687
688     // 
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.
694     //
695
696     PROCProcessLock();
697     fHoldingProcessLock = TRUE;
698
699     PROCAddThread(pThread, pNewThread);
700     fThreadDataAddedToProcessList = TRUE;
701
702     //
703     // Spawn the new pthread
704     //
705
706 #if PTHREAD_CREATE_MODIFIES_ERRNO
707     storedErrno = errno;
708 #endif  // PTHREAD_CREATE_MODIFIES_ERRNO
709
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);
714
715 #if PTHREAD_CREATE_MODIFIES_ERRNO
716     if (iError == 0)
717     {
718         // Restore errno if pthread_create succeeded.
719         errno = storedErrno;
720     }
721 #endif  // PTHREAD_CREATE_MODIFIES_ERRNO
722
723     if (0 != iError)
724     {
725         ERROR("pthread_create failed, error is %d (%s)\n", iError, strerror(iError));
726         palError = ERROR_NOT_ENOUGH_MEMORY;
727         goto EXIT;
728     }
729        
730     //
731     // Wait for the new thread to finish its initial startup tasks
732     // (i.e., the ones that might fail)
733     //
734     if (pNewThread->WaitForStartStatus())
735     {
736         //
737         // Everything succeeded. Store the handle for the new thread and
738         // the thread's ID in the out params
739         //
740         *phThread = hNewThread;
741         
742         if (NULL != lpThreadId)
743         {
744             *lpThreadId = pNewThread->GetThreadId();
745         }
746     }
747     else
748     {
749         ERROR("error occurred in THREADEntry, thread creation failed.\n");
750         palError = ERROR_INTERNAL_ERROR;
751         goto EXIT;
752     }
753
754     //
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.
758     //
759     PROCProcessUnlock();
760     fHoldingProcessLock = FALSE;
761
762 EXIT:
763
764     if (fAttributesInitialized)
765     {
766         if (0 != pthread_attr_destroy(&pthreadAttr))
767         {
768             WARN("pthread_attr_destroy() failed\n");
769         }
770     }
771
772     if (NO_ERROR != palError)
773     {
774         //
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
777         // resources here
778         //
779
780         if (fThreadDataAddedToProcessList)
781         {
782             PROCRemoveThread(pThread, pNewThread);
783         }
784         // 
785         // Once we remove the thread from the process list, we can call
786         // PROCProcessUnlock.
787         //
788         if (fHoldingProcessLock)
789         {
790             PROCProcessUnlock();
791         }
792         fHoldingProcessLock = FALSE;
793     }
794
795     _ASSERT_MSG(!fHoldingProcessLock, "Exiting InternalCreateThread while still holding the process critical section.\n");
796
797     return palError;
798 }
799
800
801
802 /*++
803 Function:
804   ExitThread
805
806 See MSDN doc.
807 --*/
808 PAL_NORETURN
809 VOID
810 PALAPI
811 ExitThread(
812        IN DWORD dwExitCode)
813 {
814     CPalThread *pThread;
815       
816     ENTRY("ExitThread(dwExitCode=%u)\n", dwExitCode);
817     PERF_ENTRY_ONLY(ExitThread);
818
819     pThread = InternalGetCurrentThread();
820
821     /* store the exit code */
822     pThread->SetExitCode(dwExitCode);
823
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);
829
830     /* kill the thread (itself), resulting in a call to InternalEndCurrentThread */
831     pthread_exit(NULL);
832     
833     ASSERT("pthread_exit should not return!\n");
834     for (;;);
835 }
836
837 /*++
838 Function:
839   GetExitCodeThread
840
841 See MSDN doc.
842 --*/
843 BOOL
844 PALAPI
845 GetExitCodeThread(
846            IN HANDLE hThread,
847            IN LPDWORD lpExitCode)
848 {
849     PAL_ERROR palError = NO_ERROR;
850     CPalThread *pthrCurrent = NULL;
851     CPalThread *pthrTarget = NULL;
852     IPalObject *pobjThread = NULL;
853     BOOL fExitCodeSet;
854
855     PERF_ENTRY(GetExitCodeThread);
856     ENTRY("GetExitCodeThread(hThread = %p, lpExitCode = %p)\n",
857           hThread, lpExitCode);
858
859     if (NULL == lpExitCode)
860     {
861         WARN("Got NULL lpExitCode\n");
862         palError = ERROR_INVALID_PARAMETER;
863         goto done;
864     }
865
866     pthrCurrent = InternalGetCurrentThread();
867     palError = InternalGetThreadDataFromHandle(
868         pthrCurrent,
869         hThread,
870         0,
871         &pthrTarget,
872         &pobjThread
873         );
874
875     pthrTarget->Lock(pthrCurrent);
876
877     fExitCodeSet = pthrTarget->GetExitCode(lpExitCode);
878     if (!fExitCodeSet)
879     {
880         if (TS_DONE == pthrTarget->synchronizationInfo.GetThreadState())
881         {
882 #ifdef FEATURE_PAL_SXS
883             // The thread exited without ever calling ExitThread.
884             // It must have wandered in.
885             *lpExitCode = 0;
886 #else // FEATURE_PAL_SXS
887             ASSERT("exit code not set but thread is dead\n");
888 #endif // FEATURE_PAL_SXS
889         }
890         else
891         {
892             *lpExitCode = STILL_ACTIVE;
893         }
894     }
895
896     pthrTarget->Unlock(pthrCurrent);
897
898 done:
899     if (NULL != pobjThread)
900     {
901         pobjThread->ReleaseReference(pthrCurrent);
902     }
903
904     LOGEXIT("GetExitCodeThread returns BOOL %d\n", NO_ERROR == palError);
905     PERF_EXIT(GetExitCodeThread);
906     
907     return NO_ERROR == palError;
908 }
909
910
911 /*++
912 Function:
913   InternalEndCurrentThread
914
915 Does any necessary memory clean up, signals waiting threads, and then forces
916 the current thread to exit.
917 --*/
918
919 VOID
920 CorUnix::InternalEndCurrentThread(
921     CPalThread *pThread
922     )
923 {
924     PAL_ERROR palError = NO_ERROR;
925     ISynchStateController *pSynchStateController = NULL;
926     
927 #ifdef PAL_PERF
928     PERFDisableThreadProfile(UserCreatedThread != pThread->GetThreadType());
929 #endif
930
931     //
932     // Abandon any objects owned by this thread
933     //
934
935     palError = g_pSynchronizationManager->AbandonObjectsOwnedByThread(
936         pThread,
937         pThread
938         );
939
940     if (NO_ERROR != palError)
941     {
942         ERROR("Failure abandoning owned objects");
943     }
944
945     //
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?
949     //
950
951     pThread->suspensionInfo.AcquireSuspensionLock(pThread);
952     IncrementEndingThreadCount();
953     pThread->synchronizationInfo.SetThreadState(TS_DONE);
954     pThread->suspensionInfo.ReleaseSuspensionLock(pThread);
955
956     //
957     // Mark the thread object as signaled
958     //
959
960     palError = pThread->GetThreadObject()->GetSynchStateController(
961         pThread,
962         &pSynchStateController
963         );
964
965     if (NO_ERROR == palError)
966     {
967         palError = pSynchStateController->SetSignalCount(1);
968         if (NO_ERROR != palError)
969         {
970             ASSERT("Unable to mark thread object as signaled");
971         }
972
973         pSynchStateController->ReleaseController();
974     }
975     else
976     {
977         ASSERT("Unable to obtain state controller for thread");
978     }
979
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)
985     {
986         TRACE("Last thread is exiting\n");
987         DecrementEndingThreadCount();
988         TerminateCurrentProcessNoExit(FALSE);
989     }
990     else
991 #endif // !FEATURE_PAL_SXS
992     {
993         /* Do this ONLY if we aren't the last thread -> otherwise
994            it gets done by TerminateProcess->
995            PROCCleanupProcess->PALShutdown->PAL_Terminate */
996
997         //
998         // Add a reference to the thread data before releasing the
999         // thread object, so we can still use it
1000         //
1001
1002         pThread->AddThreadReference();
1003
1004         //
1005         // Release the reference to the IPalObject for this thread
1006         //
1007
1008         pThread->GetThreadObject()->ReleaseReference(pThread);
1009
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) */
1013         
1014         PROCRemoveThread(pThread, pThread);
1015
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
1021         
1022         
1023         //
1024         // Now release our reference to the thread data. We cannot touch
1025         // it after this point
1026         //
1027
1028         pThread->ReleaseThreadReference();
1029         DecrementEndingThreadCount();
1030         
1031     }
1032 }
1033
1034 /*++
1035 Function:
1036   GetThreadPriority
1037
1038 See MSDN doc.
1039 --*/
1040 int
1041 PALAPI
1042 GetThreadPriority(
1043           IN HANDLE hThread)
1044 {
1045     CPalThread *pThread;
1046     PAL_ERROR palError;
1047     int iPriority = THREAD_PRIORITY_ERROR_RETURN;
1048     
1049     PERF_ENTRY(GetThreadPriority);
1050     ENTRY("GetThreadPriority(hThread=%p)\n", hThread);
1051
1052     pThread = InternalGetCurrentThread();
1053
1054     palError = InternalGetThreadPriority(
1055         pThread,
1056         hThread,
1057         &iPriority
1058         );
1059
1060     if (NO_ERROR != palError)
1061     {
1062         pThread->SetLastError(palError);
1063     }
1064
1065     LOGEXIT("GetThreadPriorityExit returns int %d\n", iPriority);
1066     PERF_EXIT(GetThreadPriority);
1067     
1068     return iPriority;
1069 }
1070
1071 PAL_ERROR
1072 CorUnix::InternalGetThreadPriority(
1073     CPalThread *pThread,
1074     HANDLE hThread,
1075     int *piPriority
1076     )
1077 {
1078     PAL_ERROR palError = NO_ERROR;
1079     CPalThread *pTargetThread;
1080     IPalObject *pobjThread = NULL;
1081     
1082     palError = InternalGetThreadDataFromHandle(
1083         pThread,
1084         hThread,
1085         0,  // THREAD_QUERY_INFORMATION
1086         &pTargetThread,
1087         &pobjThread
1088         );
1089
1090     if (NO_ERROR != palError)
1091     {
1092         goto InternalGetThreadPriorityExit;
1093     }
1094     
1095     pTargetThread->Lock(pThread);
1096
1097     *piPriority = pTargetThread->GetThreadPriority();
1098
1099     pTargetThread->Unlock(pThread);
1100
1101 InternalGetThreadPriorityExit:
1102
1103     if (NULL != pobjThread)
1104     {
1105         pobjThread->ReleaseReference(pThread);
1106     }
1107
1108     return palError;
1109 }
1110
1111
1112 /*++
1113 Function:
1114   SetThreadPriority
1115
1116 See MSDN doc.
1117 --*/
1118 BOOL
1119 PALAPI
1120 SetThreadPriority(
1121           IN HANDLE hThread,
1122           IN int nPriority)
1123 {
1124     CPalThread *pThread;
1125     PAL_ERROR palError = NO_ERROR;
1126     
1127     PERF_ENTRY(SetThreadPriority);
1128     ENTRY("SetThreadPriority(hThread=%p, nPriority=%#x)\n", hThread, nPriority);
1129
1130     pThread = InternalGetCurrentThread();
1131
1132     palError = InternalSetThreadPriority(
1133         pThread,
1134         hThread,
1135         nPriority
1136         );
1137
1138     if (NO_ERROR != palError)
1139     {
1140         pThread->SetLastError(palError);
1141     }
1142
1143     LOGEXIT("SetThreadPriority returns BOOL %d\n", NO_ERROR == palError);
1144     PERF_EXIT(SetThreadPriority);
1145     
1146     return NO_ERROR == palError;
1147 }
1148
1149 PAL_ERROR
1150 CorUnix::InternalSetThreadPriority(
1151     CPalThread *pThread,
1152     HANDLE hTargetThread,
1153     int iNewPriority
1154     )
1155 {
1156     PAL_ERROR palError = NO_ERROR;
1157     CPalThread *pTargetThread = NULL;
1158     IPalObject *pobjThread = NULL;
1159     
1160     int policy;
1161     struct sched_param schedParam;
1162     int max_priority;
1163     int min_priority;
1164     float posix_priority;
1165
1166
1167     palError = InternalGetThreadDataFromHandle(
1168         pThread,
1169         hTargetThread,
1170         0, // THREAD_SET_INFORMATION
1171         &pTargetThread,
1172         &pobjThread
1173         );
1174
1175     if (NO_ERROR != palError)
1176     {
1177         goto InternalSetThreadPriorityExit;
1178     }
1179
1180     pTargetThread->Lock(pThread);
1181
1182     /* validate the requested priority */
1183     switch (iNewPriority)
1184     {
1185     case THREAD_PRIORITY_TIME_CRITICAL: /* fall through */
1186     case THREAD_PRIORITY_IDLE:
1187         break;
1188
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,
1196            and exit */
1197         pTargetThread->m_iThreadPriority = iNewPriority;
1198         goto InternalSetThreadPriorityExit;        
1199 #endif
1200         break;
1201
1202     default:
1203         ASSERT("Priority %d not supported\n", iNewPriority);
1204         palError = ERROR_INVALID_PARAMETER;
1205         goto InternalSetThreadPriorityExit;
1206     }  
1207
1208     /* check if the thread is still running */
1209     if (TS_DONE == pTargetThread->synchronizationInfo.GetThreadState())
1210     {
1211         /* the thread has exited, set the priority in the thread structure 
1212            and exit */
1213         pTargetThread->m_iThreadPriority = iNewPriority;
1214         goto InternalSetThreadPriorityExit;        
1215     }
1216
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(),
1221             &policy, 
1222             &schedParam
1223             ) != 0)
1224     {
1225         ASSERT("Unable to get current thread scheduling information\n");
1226         palError = ERROR_INTERNAL_ERROR;
1227         goto InternalSetThreadPriorityExit;
1228     }
1229
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.
1233     */
1234     if (policy == SCHED_OTHER)
1235     {
1236         TRACE("Pthread priority levels for SCHED_OTHER cannot be reassigned on this platform\n");
1237         goto InternalSetThreadPriorityExit;
1238     }
1239 #endif
1240
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)
1245     {
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;
1250     }
1251 #else
1252     max_priority = PAL_THREAD_PRIORITY_MAX;
1253     min_priority = PAL_THREAD_PRIORITY_MIN;
1254 #endif
1255
1256     TRACE("Pthread priorities for policy %d must be in the range %d to %d\n", 
1257           policy, min_priority, max_priority);
1258
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. 
1266        We do this by :
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. 
1276         
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
1283     */
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;
1288
1289     schedParam.sched_priority = (int)posix_priority;
1290     
1291     TRACE("PAL priority %d is mapped to pthread priority %d\n",
1292           iNewPriority, schedParam.sched_priority);
1293
1294     /* Finally, set the new priority into place */
1295     if (pthread_setschedparam(
1296             pTargetThread->GetPThreadSelf(),
1297             policy,
1298             &schedParam
1299             ) != 0)
1300     {
1301 #if SET_SCHEDPARAM_NEEDS_PRIVS
1302         if (EPERM == errno)
1303         {
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;
1308         }
1309 #endif
1310         
1311         ASSERT("Unable to set thread priority (errno %d)\n", errno);
1312         palError = ERROR_INTERNAL_ERROR;
1313         goto InternalSetThreadPriorityExit;
1314     }
1315     
1316     pTargetThread->m_iThreadPriority = iNewPriority;
1317
1318 InternalSetThreadPriorityExit:
1319
1320     if (NULL != pTargetThread)
1321     {
1322         pTargetThread->Unlock(pThread);
1323     }
1324
1325     if (NULL != pobjThread)
1326     {
1327         pobjThread->ReleaseReference(pThread);
1328     }
1329
1330     return palError;    
1331 }
1332
1333 BOOL
1334 CorUnix::GetThreadTimesInternal(
1335     IN HANDLE hThread,
1336     OUT LPFILETIME lpKernelTime,
1337     OUT LPFILETIME lpUserTime)
1338 {
1339     __int64 calcTime;
1340     BOOL retval = FALSE;
1341     const __int64 SECS_TO_NS = 1000000000; /* 10^9 */
1342     const __int64 USECS_TO_NS = 1000;      /* 10^3 */
1343
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;
1351
1352     pthrCurrent = InternalGetCurrentThread();
1353     palError = InternalGetThreadDataFromHandle(
1354         pthrCurrent,
1355         hThread,
1356         0,
1357         &pthrTarget,
1358         &pobjThread
1359         );
1360     
1361     if (palError != NO_ERROR)
1362     {
1363         ASSERT("Unable to get thread data from handle %p"
1364               "thread\n", hThread);
1365         SetLastError(ERROR_INTERNAL_ERROR);
1366         goto SetTimesToZero;
1367     }   
1368
1369     pthrTarget->Lock(pthrCurrent);
1370     
1371     mach_port_t mhThread;
1372     mhThread = pthread_mach_thread_np(pthrTarget->GetPThreadSelf());
1373     
1374     kern_return_t status;
1375     status = thread_info(
1376         mhThread, 
1377         THREAD_BASIC_INFO, 
1378         (thread_info_t)&resUsage, 
1379         &resUsage_count);
1380
1381     pthrTarget->Unlock(pthrCurrent);
1382
1383     if (status != KERN_SUCCESS)
1384     {
1385         ASSERT("Unable to get resource usage information for the current "
1386               "thread\n");
1387         SetLastError(ERROR_INTERNAL_ERROR);
1388         goto SetTimesToZero;
1389     }
1390
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);
1397
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);
1404
1405     retval = TRUE;
1406
1407     goto GetThreadTimesInternalExit;
1408
1409 #elif defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID /* Currently unimplemented */
1410
1411     PAL_ERROR palError;
1412     CPalThread *pThread;
1413     CPalThread *pTargetThread;
1414     IPalObject *pobjThread = NULL;
1415     kvm_t *kd;
1416     int cnt, nlwps;
1417     struct kinfo_lwp *klwp;
1418     int i;
1419     bool found = false;
1420
1421     pThread = InternalGetCurrentThread();
1422
1423     palError = InternalGetThreadDataFromHandle(
1424         pThread,
1425         hThread,
1426         0, // THREAD_GET_CONTEXT
1427         &pTargetThread,
1428         &pobjThread
1429         );
1430     if (palError != NO_ERROR)
1431     {
1432         ASSERT("Unable to get thread data from handle %p"
1433               "thread\n", hThread);
1434         SetLastError(ERROR_INTERNAL_ERROR);
1435         goto SetTimesToZero;
1436     }
1437
1438     kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
1439     if (kd == NULL)
1440     {
1441         ASSERT("kvm_open(3) error");
1442         SetLastError(ERROR_INTERNAL_ERROR);
1443         goto SetTimesToZero;
1444     }
1445
1446     pTargetThread->Lock(pThread);
1447
1448     klwp = kvm_getlwps(kd, getpid(), 0, sizeof(struct kinfo_lwp), &nlwps);
1449     if (klwp == NULL || nlwps < 1)
1450     {
1451         kvm_close(kd);
1452         ASSERT("Unable to get clock from %p thread\n", hThread);
1453         SetLastError(ERROR_INTERNAL_ERROR);
1454         pTargetThread->Unlock(pThread);
1455         goto SetTimesToZero;
1456     }
1457
1458     for (i = 0; i < nlwps; i++)
1459     {
1460         if (klwp[i].l_lid == THREADSilentGetCurrentThreadId())
1461         {
1462             found = true;
1463             break;
1464         }
1465     }
1466
1467     if (!found)
1468     {
1469         kvm_close(kd);
1470         ASSERT("Unable to get clock from %p thread\n", hThread);
1471         SetLastError(ERROR_INTERNAL_ERROR);
1472         pTargetThread->Unlock(pThread);
1473         goto SetTimesToZero;
1474     }
1475
1476     pTargetThread->Unlock(pThread);
1477
1478     kvm_close(kd);
1479
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);
1484
1485     /* NetBSD as of (7.0) doesn't differentiate used time in user/kernel for lwp */
1486     lpKernelTime->dwLowDateTime = 0;
1487     lpKernelTime->dwHighDateTime = 0;
1488
1489     retval = TRUE;
1490     goto GetThreadTimesInternalExit;
1491
1492 #else //HAVE_MACH_THREADS
1493
1494     PAL_ERROR palError;
1495     CPalThread *pThread;
1496     CPalThread *pTargetThread;
1497     IPalObject *pobjThread = NULL;
1498     clockid_t cid;
1499
1500     pThread = InternalGetCurrentThread();
1501
1502     palError = InternalGetThreadDataFromHandle(
1503         pThread,
1504         hThread,
1505         0, // THREAD_GET_CONTEXT
1506         &pTargetThread,
1507         &pobjThread
1508         );
1509     if (palError != NO_ERROR)
1510     {
1511         ASSERT("Unable to get thread data from handle %p"
1512               "thread\n", hThread);
1513         SetLastError(ERROR_INTERNAL_ERROR);
1514         goto SetTimesToZero;
1515     }   
1516
1517     pTargetThread->Lock(pThread);
1518
1519 #if HAVE_PTHREAD_GETCPUCLOCKID
1520     if (pthread_getcpuclockid(pTargetThread->GetPThreadSelf(), &cid) != 0)
1521 #endif
1522     {
1523         ASSERT("Unable to get clock from thread\n", hThread);
1524         SetLastError(ERROR_INTERNAL_ERROR);
1525         pTargetThread->Unlock(pThread);
1526         goto SetTimesToZero;
1527     }
1528
1529     struct timespec ts;
1530     if (clock_gettime(cid, &ts) != 0)
1531     {
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;
1536     }
1537
1538     pTargetThread->Unlock(pThread);
1539
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);
1545     
1546     /* Set kernel time to zero, for now */
1547     lpKernelTime->dwLowDateTime = 0;
1548     lpKernelTime->dwHighDateTime = 0;
1549
1550     retval = TRUE;
1551     goto GetThreadTimesInternalExit;
1552
1553 #endif //HAVE_MACH_THREADS
1554
1555 SetTimesToZero:
1556     
1557     lpUserTime->dwLowDateTime = 0;
1558     lpUserTime->dwHighDateTime = 0;
1559     lpKernelTime->dwLowDateTime = 0;
1560     lpKernelTime->dwHighDateTime = 0;
1561     goto GetThreadTimesInternalExit;
1562
1563 GetThreadTimesInternalExit:
1564     return retval;
1565 }
1566
1567 /*++
1568 Function:
1569   GetThreadTimes
1570
1571 See MSDN doc.
1572 --*/
1573 BOOL
1574 PALAPI
1575 GetThreadTimes(
1576         IN HANDLE hThread,
1577         OUT LPFILETIME lpCreationTime,
1578         OUT LPFILETIME lpExitTime,
1579         OUT LPFILETIME lpKernelTime,
1580         OUT LPFILETIME lpUserTime)
1581 {
1582     PERF_ENTRY(GetThreadTimes);
1583     ENTRY("GetThreadTimes(hThread=%p, lpExitTime=%p, lpKernelTime=%p,"
1584           "lpUserTime=%p)\n",
1585           hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime );
1586
1587     FILETIME KernelTime, UserTime;
1588
1589     BOOL retval = GetThreadTimesInternal(hThread, &KernelTime, &UserTime);
1590
1591     /* Not sure if this still needs to be here */
1592     /*
1593     TRACE ("thread_info User: %ld sec,%ld microsec. Kernel: %ld sec,%ld"
1594            " microsec\n",
1595            resUsage.user_time.seconds, resUsage.user_time.microseconds,
1596            resUsage.system_time.seconds, resUsage.system_time.microseconds);
1597     */
1598
1599     __int64 calcTime;
1600     if (lpUserTime)
1601     {
1602         /* Produce the time in 100s of ns */
1603         calcTime = ((ULONG64)UserTime.dwHighDateTime << 32);
1604         calcTime += (ULONG64)UserTime.dwLowDateTime;
1605         calcTime /= 100;
1606         lpUserTime->dwLowDateTime = (DWORD)calcTime;
1607         lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1608     }
1609     if (lpKernelTime)
1610     {
1611         /* Produce the time in 100s of ns */
1612         calcTime = ((ULONG64)KernelTime.dwHighDateTime << 32);
1613         calcTime += (ULONG64)KernelTime.dwLowDateTime;
1614         calcTime /= 100;
1615         lpKernelTime->dwLowDateTime = (DWORD)calcTime;
1616         lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
1617     }
1618     //Set CreationTime and Exit time to zero for now - maybe change this later?
1619     if (lpCreationTime)
1620     {
1621         lpCreationTime->dwLowDateTime = 0;
1622         lpCreationTime->dwHighDateTime = 0;
1623     }
1624     
1625     if (lpExitTime)
1626     {
1627         lpExitTime->dwLowDateTime = 0;
1628         lpExitTime->dwHighDateTime = 0;
1629     }
1630     
1631     LOGEXIT("GetThreadTimes returns BOOL %d\n", retval);
1632     PERF_EXIT(GetThreadTimes);
1633     return (retval);
1634 }
1635
1636
1637
1638 void *
1639 CPalThread::ThreadEntry(
1640     void *pvParam
1641     )
1642 {
1643     PAL_ERROR palError;
1644     CPalThread *pThread;
1645     PTHREAD_START_ROUTINE pfnStartRoutine;
1646     LPVOID pvPar;
1647     DWORD retValue;
1648
1649     pThread = reinterpret_cast<CPalThread*>(pvParam);
1650
1651     if (NULL == pThread)
1652     {
1653         ASSERT("THREAD pointer is NULL!\n");
1654         goto fail;
1655     }
1656
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)
1662         DebugBreak();
1663 #endif // FEATURE_PAL_SXS && _DEBUG
1664
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);
1669 #endif
1670 #if HAVE_THREAD_SELF
1671     pThread->m_dwLwpId = (DWORD) thread_self();
1672 #elif HAVE__LWP_SELF
1673     pThread->m_dwLwpId = (DWORD) _lwp_self();
1674 #else
1675     pThread->m_dwLwpId = 0;
1676 #endif
1677
1678     palError = pThread->RunPostCreateInitializers();
1679     if (NO_ERROR != palError)
1680     {
1681         ASSERT("Error %i initializing thread data (post creation)\n", palError);
1682         goto fail;
1683     }
1684
1685     // Check if the thread should be started suspended.
1686     if (pThread->GetCreateSuspended())
1687     {
1688         palError = pThread->suspensionInfo.InternalSuspendNewThreadFromData(pThread);
1689         if (NO_ERROR != palError)
1690         {
1691             ASSERT("Error %i attempting to suspend new thread\n", palError);
1692             goto fail;
1693         }
1694
1695         //
1696         // We need to run any APCs that have already been queued for
1697         // this thread.
1698         //
1699
1700         (void) g_pSynchronizationManager->DispatchPendingAPCs(pThread);
1701     }
1702     else
1703     {
1704         //
1705         // All startup operations that might have failed have succeeded,
1706         // so thread creation is successful. Let CreateThread return.
1707         //
1708
1709         pThread->SetStartStatus(TRUE);
1710     }
1711
1712     pThread->synchronizationInfo.SetThreadState(TS_RUNNING);
1713
1714     if (UserCreatedThread == pThread->GetThreadType())
1715     {
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);
1720     }
1721
1722 #ifdef PAL_PERF
1723     PERFAllocThreadInfo();
1724     PERFEnableThreadProfile(UserCreatedThread != pThread->GetThreadType());
1725 #endif
1726
1727     /* call the startup routine */
1728     pfnStartRoutine = pThread->GetStartAddress();
1729     pvPar = pThread->GetStartParameter();
1730
1731     retValue = (*pfnStartRoutine)(pvPar);
1732
1733     TRACE("Thread exited (%u)\n", retValue);
1734     ExitThread(retValue);
1735
1736     /* Note: never get here */ 
1737     ASSERT("ExitThread failed!\n");
1738     for (;;);
1739
1740 fail:
1741
1742     //
1743     // Notify InternalCreateThread that a failure occurred
1744     //
1745     
1746     if (NULL != pThread)
1747     {
1748         pThread->synchronizationInfo.SetThreadState(TS_FAILED);
1749         pThread->SetStartStatus(FALSE);
1750     }
1751
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 */
1755     return NULL;
1756 }
1757
1758
1759 #define PAL_THREAD_DEFAULT_STACK_SIZE "PAL_THREAD_DEFAULT_STACK_SIZE"
1760
1761 PAL_ERROR
1762 CorUnix::InitializeGlobalThreadData(
1763     void
1764     )
1765 {
1766     PAL_ERROR palError = NO_ERROR;
1767     char *pszStackSize = NULL;
1768
1769     //
1770     // Read in the environment to see whether we need to change the default
1771     // thread stack size.
1772     //
1773     pszStackSize = EnvironGetenv(PAL_THREAD_DEFAULT_STACK_SIZE);
1774     if (NULL != pszStackSize)
1775     {
1776         // Environment variable exists
1777         char *pszEnd;
1778         DWORD dw = PAL_strtoul(pszStackSize, &pszEnd, 16); // treat it as hex
1779         if ( (pszStackSize != pszEnd) && (0 != dw) )
1780         {
1781             CPalThread::s_dwDefaultThreadStackSize = dw;
1782         }
1783
1784         free(pszStackSize);
1785     }
1786
1787     return palError;
1788 }
1789
1790
1791 /*++
1792 Function:
1793     CreateThreadData
1794
1795 Abstract:
1796     Create the CPalThread for the startup thread
1797     or another external thread entering the PAL
1798     for the first time
1799   
1800 Parameters:
1801     ppThread - on success, receives the CPalThread
1802
1803 Return:
1804    PAL_ERROR
1805 --*/
1806
1807 PAL_ERROR
1808 CorUnix::CreateThreadData(
1809     CPalThread **ppThread
1810     )
1811 {
1812     PAL_ERROR palError = NO_ERROR;
1813     CPalThread *pThread = NULL;
1814     
1815     /* Create the thread object */
1816     pThread = AllocTHREAD();
1817
1818     if (NULL == pThread)
1819     {
1820        palError = ERROR_OUTOFMEMORY;
1821        goto CreateThreadDataExit;
1822     }
1823
1824     palError = pThread->RunPreCreateInitializers();
1825
1826     if (NO_ERROR != palError)
1827     {
1828         goto CreateThreadDataExit;
1829     }
1830
1831     pThread->SetLastError(0);
1832
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);
1837 #endif
1838 #if HAVE_THREAD_SELF
1839     pThread->m_dwLwpId = (DWORD) thread_self();
1840 #elif HAVE__LWP_SELF
1841     pThread->m_dwLwpId = (DWORD) _lwp_self();
1842 #else
1843     pThread->m_dwLwpId = 0;
1844 #endif
1845
1846     palError = pThread->RunPostCreateInitializers();
1847     if (NO_ERROR != palError)
1848     {
1849         goto CreateThreadDataExit;
1850     }
1851
1852     *ppThread = pThread;
1853     
1854 CreateThreadDataExit:
1855
1856     if (NO_ERROR != palError)
1857     {
1858         if (NULL != pThread)
1859         {
1860             pThread->ReleaseThreadReference();
1861         }
1862     }
1863
1864     return palError;
1865 }
1866
1867 /*++
1868 Function:
1869     CreateThreadData
1870
1871 Abstract:
1872     Creates the IPalObject for a thread, storing
1873     the reference in the CPalThread
1874   
1875 Parameters:
1876     pThread - the thread data for the creating thread
1877     pNewThread - the thread data for the thread being initialized
1878
1879 Return:
1880    PAL_ERROR
1881 --*/
1882
1883 PAL_ERROR
1884 CorUnix::CreateThreadObject(
1885     CPalThread *pThread,
1886     CPalThread *pNewThread,
1887     HANDLE *phThread
1888     )
1889 {
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;
1898
1899     //
1900     // Create the IPalObject for the thread
1901     //
1902
1903     palError = g_pObjectManager->AllocateObject(
1904         pThread,
1905         &otThread,
1906         &oa,
1907         &pobjThread
1908         );
1909
1910     if (NO_ERROR != palError)
1911     {
1912         goto CreateThreadObjectExit;
1913     }
1914
1915     //
1916     // Store the CPalThread inside of the IPalObject
1917     //
1918
1919     palError = pobjThread->GetProcessLocalData(
1920         pThread,
1921         WriteLock, 
1922         &pDataLock,
1923         reinterpret_cast<void **>(&pLocalData)
1924         );
1925
1926     if (NO_ERROR != palError)
1927     {
1928         goto CreateThreadObjectExit;
1929     }
1930
1931     pLocalData->pThread = pNewThread;
1932     pDataLock->ReleaseLock(pThread, TRUE);
1933     fThreadDataStoredInObject = TRUE;
1934
1935     //
1936     // Register the IPalObject (obtaining a handle)
1937     //
1938
1939     palError = g_pObjectManager->RegisterObject(
1940         pThread,
1941         pobjThread,
1942         &aotThread,
1943         0, //THREAD_ALL_ACCESS,
1944         &hThread,
1945         &pobjRegisteredThread
1946         );
1947         
1948     //
1949     // pobjThread is invalidated by the call to RegisterObject, so NULL
1950     // it out here to prevent it from being released
1951     //
1952
1953     pobjThread = NULL;
1954
1955     if (NO_ERROR != palError)
1956     {
1957         goto CreateThreadObjectExit;
1958     }
1959
1960     //
1961     // Store the registered object inside of the thread object,
1962     // adding a reference for the thread itself
1963     //
1964
1965     pNewThread->m_pThreadObject = pobjRegisteredThread;
1966     pNewThread->m_pThreadObject->AddReference();
1967
1968     *phThread = hThread;
1969
1970 CreateThreadObjectExit:
1971
1972     if (NO_ERROR != palError)
1973     {
1974         if (NULL != hThread)
1975         {
1976             g_pObjectManager->RevokeHandle(pThread, hThread);
1977         }
1978
1979         if (NULL != pNewThread->m_pThreadObject)
1980         {
1981             //
1982             // Release the new thread's reference on the underlying thread
1983             // object
1984             //
1985
1986             pNewThread->m_pThreadObject->ReleaseReference(pThread);
1987         }
1988
1989         if (!fThreadDataStoredInObject)
1990         {
1991             //
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)
1996             //
1997
1998             pNewThread->ReleaseThreadReference();            
1999         }
2000     }
2001
2002     if (NULL != pobjThread)
2003     {
2004         pobjThread->ReleaseReference(pThread);
2005     }
2006
2007     if (NULL != pobjRegisteredThread)
2008     {
2009         pobjRegisteredThread->ReleaseReference(pThread);
2010     }
2011
2012     return palError;
2013 }
2014
2015 PAL_ERROR
2016 CorUnix::InternalCreateDummyThread(
2017     CPalThread *pThread,
2018     LPSECURITY_ATTRIBUTES lpThreadAttributes,
2019     CPalThread **ppDummyThread,
2020     HANDLE *phThread
2021     )
2022 {
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;
2031
2032     pDummyThread = AllocTHREAD();
2033     if (NULL == pDummyThread)
2034     {
2035         palError = ERROR_OUTOFMEMORY;
2036         goto InternalCreateDummyThreadExit;
2037     }
2038
2039     pDummyThread->m_fIsDummy = TRUE;
2040
2041     palError = g_pObjectManager->AllocateObject(
2042         pThread,
2043         &otThread,
2044         &oa,
2045         &pobjThread
2046         );
2047
2048     if (NO_ERROR != palError)
2049     {
2050         goto InternalCreateDummyThreadExit;
2051     }
2052
2053     palError = pobjThread->GetProcessLocalData(
2054         pThread,
2055         WriteLock,
2056         &pDataLock,
2057         reinterpret_cast<void **>(&pLocalData)
2058         );
2059
2060     if (NO_ERROR != palError)
2061     {
2062         goto InternalCreateDummyThreadExit;
2063     }
2064
2065     pLocalData->pThread = pDummyThread;
2066     pDataLock->ReleaseLock(pThread, TRUE);
2067     fThreadDataStoredInObject = TRUE;
2068
2069     palError = g_pObjectManager->RegisterObject(
2070         pThread,
2071         pobjThread,
2072         &aotThread,
2073         0, // THREAD_ALL_ACCESS
2074         phThread,
2075         &pobjThreadRegistered
2076         );
2077
2078     //
2079     // pobjThread is invalidated by the above call, so NULL
2080     // it out here
2081     //
2082     
2083     pobjThread = NULL;
2084
2085     if (NO_ERROR != palError)
2086     {
2087         goto InternalCreateDummyThreadExit;
2088     }
2089
2090     //
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...)
2095     //
2096
2097     *ppDummyThread = pDummyThread;
2098
2099 InternalCreateDummyThreadExit:
2100
2101     if (NULL != pobjThreadRegistered)
2102     {
2103         pobjThreadRegistered->ReleaseReference(pThread);
2104     }
2105
2106     if (NULL != pobjThread)
2107     {
2108         pobjThread->ReleaseReference(pThread);
2109     }
2110
2111     if (NO_ERROR != palError
2112         && NULL != pDummyThread
2113         && !fThreadDataStoredInObject)
2114     {
2115         pDummyThread->ReleaseThreadReference();
2116     }
2117
2118     return palError;
2119 }
2120
2121 PAL_ERROR
2122 CorUnix::InternalGetThreadDataFromHandle(
2123     CPalThread *pThread,
2124     HANDLE hThread,
2125     DWORD dwRightsRequired,
2126     CPalThread **ppTargetThread,
2127     IPalObject **ppobjThread
2128     )
2129 {
2130     PAL_ERROR palError = NO_ERROR;
2131     IPalObject *pobj;
2132     IDataLock *pLock;
2133     CThreadProcessLocalData *pData;
2134
2135     *ppobjThread = NULL;
2136
2137     if (hPseudoCurrentThread == hThread)
2138     {
2139         *ppTargetThread = pThread;
2140     }
2141     else
2142     {
2143         palError = g_pObjectManager->ReferenceObjectByHandle(
2144             pThread,
2145             hThread,
2146             &aotThread,
2147             dwRightsRequired,
2148             &pobj
2149             );
2150
2151         if (NO_ERROR == palError)
2152         {
2153             palError = pobj->GetProcessLocalData(
2154                 pThread,
2155                 ReadLock,
2156                 &pLock,
2157                 reinterpret_cast<void**>(&pData)
2158                 );
2159
2160             if (NO_ERROR == palError)
2161             {
2162                 *ppTargetThread = pData->pThread;
2163                 pLock->ReleaseLock(pThread, FALSE);
2164
2165                 //
2166                 // Transfer object reference to out param
2167                 //
2168
2169                 *ppobjThread = pobj;                
2170             }
2171             else
2172             {
2173                 pobj->ReleaseReference(pThread);
2174             }
2175         }
2176     }
2177
2178     return palError;
2179 }
2180
2181 PAL_ERROR
2182 CPalThread::RunPreCreateInitializers(
2183     void
2184     )
2185 {
2186     PAL_ERROR palError = NO_ERROR;
2187     int iError;
2188
2189     //
2190     // First, perform initialization of CPalThread private members
2191     //
2192
2193     InternalInitializeCriticalSection(&m_csLock);
2194     m_fLockInitialized = TRUE;
2195
2196     iError = pthread_mutex_init(&m_startMutex, NULL);
2197     if (0 != iError)
2198     {
2199         goto RunPreCreateInitializersExit;
2200     }
2201
2202     iError = pthread_cond_init(&m_startCond, NULL);
2203     if (0 != iError)
2204     {
2205         pthread_mutex_destroy(&m_startMutex);
2206         goto RunPreCreateInitializersExit;
2207     }
2208
2209     m_fStartItemsInitialized = TRUE;
2210
2211     //
2212     // Call the pre-create initializers for embedded classes
2213     //
2214
2215     palError = synchronizationInfo.InitializePreCreate();
2216     if (NO_ERROR != palError)
2217     {
2218         goto RunPreCreateInitializersExit;
2219     }
2220
2221     palError = suspensionInfo.InitializePreCreate();
2222     if (NO_ERROR != palError)
2223     {
2224         goto RunPreCreateInitializersExit;
2225     }
2226
2227     palError = sehInfo.InitializePreCreate();
2228     if (NO_ERROR != palError)
2229     {
2230         goto RunPreCreateInitializersExit;
2231     }
2232
2233     palError = tlsInfo.InitializePreCreate();
2234     if (NO_ERROR != palError)
2235     {
2236         goto RunPreCreateInitializersExit;
2237     }
2238
2239     palError = apcInfo.InitializePreCreate();
2240     if (NO_ERROR != palError)
2241     {
2242         goto RunPreCreateInitializersExit;
2243     }
2244
2245     palError = crtInfo.InitializePreCreate();
2246     if (NO_ERROR != palError)
2247     {
2248         goto RunPreCreateInitializersExit;
2249     }
2250
2251 RunPreCreateInitializersExit:
2252
2253     return palError;
2254 }
2255
2256 CPalThread::~CPalThread()
2257 {
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.
2267
2268     if (m_fLockInitialized)
2269     {
2270         InternalDeleteCriticalSection(&m_csLock);
2271     }
2272
2273     if (m_fStartItemsInitialized)
2274     {
2275         int iError;
2276         
2277         iError = pthread_cond_destroy(&m_startCond);
2278         _ASSERTE(0 == iError);
2279         
2280         iError = pthread_mutex_destroy(&m_startMutex);
2281         _ASSERTE(0 == iError);
2282     }
2283 }
2284
2285 void
2286 CPalThread::AddThreadReference(
2287     void
2288     )
2289 {
2290     InterlockedIncrement(&m_lRefCount);
2291 }
2292
2293 void
2294 CPalThread::ReleaseThreadReference(
2295     void
2296     )
2297 {
2298     LONG lRefCount = InterlockedDecrement(&m_lRefCount);
2299     _ASSERT_MSG(lRefCount >= 0, "Released a thread and ended with a negative refcount (%ld)\n", lRefCount);
2300     if (0 == lRefCount)
2301     {
2302         FreeTHREAD(this);
2303     }
2304     
2305 }
2306
2307 PAL_ERROR
2308 CPalThread::RunPostCreateInitializers(
2309     void
2310     )
2311 {
2312     PAL_ERROR palError = NO_ERROR;
2313
2314     //
2315     // Call the post-create initializers for embedded classes
2316     //
2317
2318     palError = synchronizationInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2319     if (NO_ERROR != palError)
2320     {
2321         goto RunPostCreateInitializersExit;
2322     }
2323
2324     palError = suspensionInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2325     if (NO_ERROR != palError)
2326     {
2327         goto RunPostCreateInitializersExit;
2328     }
2329
2330     palError = sehInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2331     if (NO_ERROR != palError)
2332     {
2333         goto RunPostCreateInitializersExit;
2334     }
2335
2336     palError = tlsInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2337     if (NO_ERROR != palError)
2338     {
2339         goto RunPostCreateInitializersExit;
2340     }
2341
2342     palError = apcInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2343     if (NO_ERROR != palError)
2344     {
2345         goto RunPostCreateInitializersExit;
2346     }
2347
2348     palError = crtInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
2349     if (NO_ERROR != palError)
2350     {
2351         goto RunPostCreateInitializersExit;
2352     }
2353
2354 #ifdef FEATURE_PAL_SXS
2355     _ASSERTE(m_fInPal);
2356     palError = SEHEnable(this);
2357     if (NO_ERROR != palError)
2358     {
2359         goto RunPostCreateInitializersExit;
2360     }
2361 #endif // FEATURE_PAL_SXS
2362
2363 RunPostCreateInitializersExit:
2364
2365     return palError;
2366 }
2367
2368 void
2369 CPalThread::SetStartStatus(
2370     bool fStartSucceeded
2371     )
2372 {
2373     int iError;
2374
2375 #if _DEBUG
2376     if (m_fStartStatusSet)
2377     {
2378         ASSERT("Multiple calls to CPalThread::SetStartStatus\n");
2379     }
2380 #endif
2381
2382     //
2383     // This routine may get called from CPalThread::ThreadEntry
2384     //
2385     // If we've reached this point there are no further thread 
2386     // suspensions that happen at creation time, so reset
2387     // m_bCreateSuspended
2388     //
2389
2390     m_bCreateSuspended = FALSE;
2391
2392     iError = pthread_mutex_lock(&m_startMutex);
2393     if (0 != iError)
2394     {
2395         ASSERT("pthread primitive failure\n");
2396         // bugcheck?
2397     }
2398
2399     m_fStartStatus = fStartSucceeded;
2400     m_fStartStatusSet = TRUE;
2401
2402     iError = pthread_cond_signal(&m_startCond);
2403     if (0 != iError)
2404     {
2405         ASSERT("pthread primitive failure\n");
2406         // bugcheck?
2407     }
2408
2409     iError = pthread_mutex_unlock(&m_startMutex);
2410     if (0 != iError)
2411     {
2412         ASSERT("pthread primitive failure\n");
2413         // bugcheck?
2414     }
2415 }
2416
2417 bool
2418 CPalThread::WaitForStartStatus(
2419     void
2420     )
2421 {
2422     int iError;
2423
2424     iError = pthread_mutex_lock(&m_startMutex);
2425     if (0 != iError)
2426     {
2427         ASSERT("pthread primitive failure\n");
2428         // bugcheck?
2429     }
2430
2431     while (!m_fStartStatusSet)
2432     {
2433         iError = pthread_cond_wait(&m_startCond, &m_startMutex);
2434         if (0 != iError)
2435         {
2436             ASSERT("pthread primitive failure\n");
2437             // bugcheck?
2438         }
2439     }
2440
2441     iError = pthread_mutex_unlock(&m_startMutex);
2442     if (0 != iError)
2443     {
2444         ASSERT("pthread primitive failure\n");
2445         // bugcheck?
2446     }
2447
2448     return m_fStartStatus;
2449 }
2450
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. */
2460
2461 void 
2462 IncrementEndingThreadCount(
2463     void
2464     )
2465 {
2466     int iError;
2467
2468     iError = pthread_mutex_lock(&ptmEndThread);
2469     _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2470
2471     iEndingThreads++;
2472
2473     iError = pthread_mutex_unlock(&ptmEndThread);
2474     _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2475 }
2476
2477 void 
2478 DecrementEndingThreadCount(
2479     void
2480     )
2481 {
2482     int iError;
2483
2484     iError = pthread_mutex_lock(&ptmEndThread);
2485     _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2486
2487     iEndingThreads--;
2488     _ASSERTE(iEndingThreads >= 0);
2489
2490     if (iEndingThreads == 0)
2491     {
2492         iError = pthread_cond_signal(&ptcEndThread);
2493         _ASSERT_MSG(iError == 0, "pthread_cond_signal returned %d\n", iError);
2494     }
2495
2496     iError = pthread_mutex_unlock(&ptmEndThread);
2497     _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2498 }
2499
2500 void 
2501 WaitForEndingThreads(
2502     void
2503     )
2504 {
2505     int iError;
2506
2507     iError = pthread_mutex_lock(&ptmEndThread);
2508     _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
2509
2510     while (iEndingThreads > 0)
2511     {
2512         iError = pthread_cond_wait(&ptcEndThread, &ptmEndThread);
2513         _ASSERT_MSG(iError == 0, "pthread_cond_wait returned %d\n", iError);  
2514     }
2515
2516     iError = pthread_mutex_unlock(&ptmEndThread);
2517     _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
2518 }
2519
2520 PAL_ERROR
2521 CorUnix::InitializeEndingThreadsData(
2522     void
2523     )
2524 {
2525     PAL_ERROR palError = ERROR_INTERNAL_ERROR;
2526     int iError;
2527
2528     iError = pthread_mutex_init(&ptmEndThread, NULL);
2529     if (0 != iError)
2530     {
2531         goto InitializeEndingThreadsDataExit;
2532     }
2533
2534     iError = pthread_cond_init(&ptcEndThread, NULL);
2535     if (0 != iError)
2536     {
2537         //
2538         // Don't bother checking the return value of pthread_mutex_destroy
2539         // since PAL initialization will now fail.
2540         //
2541         
2542         pthread_mutex_destroy(&ptmEndThread);
2543         goto InitializeEndingThreadsDataExit;
2544     }
2545
2546     palError = NO_ERROR;
2547
2548 InitializeEndingThreadsDataExit:
2549
2550     return palError;
2551 }
2552
2553 void
2554 ThreadCleanupRoutine(
2555     CPalThread *pThread,
2556     IPalObject *pObjectToCleanup,
2557     bool fShutdown,
2558     bool fCleanupSharedState
2559     )
2560 {
2561     CThreadProcessLocalData *pThreadData = NULL;
2562     CPalThread *pThreadToCleanup = NULL;
2563     IDataLock *pDataLock = NULL;
2564     PAL_ERROR palError = NO_ERROR;
2565         
2566     //
2567     // Free the CPalThread data for the passed in thread
2568     //
2569
2570     palError = pObjectToCleanup->GetProcessLocalData(
2571         pThread,
2572         WriteLock, 
2573         &pDataLock,
2574         reinterpret_cast<void**>(&pThreadData)
2575         );
2576
2577     if (NO_ERROR == palError)
2578     {
2579         //
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).
2587         //
2588         
2589         pThreadToCleanup = pThreadData->pThread;
2590         pThreadData->pThread = NULL;
2591         pDataLock->ReleaseLock(pThread, TRUE);
2592         pThreadToCleanup->ReleaseThreadReference();
2593     }
2594     else
2595     {
2596         ASSERT("Unable to obtain thread data");
2597     }
2598     
2599 }
2600
2601 PAL_ERROR
2602 ThreadInitializationRoutine(
2603     CPalThread *pThread,
2604     CObjectType *pObjectType,
2605     void *pImmutableData,
2606     void *pSharedData,
2607     void *pProcessLocalData
2608     )
2609 {
2610     return NO_ERROR;
2611 }
2612
2613 // Get base address of the current thread's stack
2614 void *
2615 CPalThread::GetStackBase()
2616 {
2617     void* stackBase;
2618 #ifdef _TARGET_MAC64
2619     // This is a Mac specific method
2620     stackBase = pthread_get_stackaddr_np(pthread_self());
2621 #else
2622     pthread_attr_t attr;
2623     void* stackAddr;
2624     size_t stackSize;
2625     int status;
2626
2627     pthread_t thread = pthread_self();
2628
2629     status = pthread_attr_init(&attr);
2630     _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
2631
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);
2636 #else
2637 #error Dont know how to get thread attributes on this platform!
2638 #endif
2639     _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
2640
2641     status = pthread_attr_getstack(&attr, &stackAddr, &stackSize);
2642     _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
2643
2644     status = pthread_attr_destroy(&attr);
2645     _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
2646
2647     stackBase = (void*)((size_t)stackAddr + stackSize);
2648 #endif
2649
2650     return stackBase;
2651 }
2652
2653 // Get limit address of the current thread's stack
2654 void *
2655 CPalThread::GetStackLimit()
2656 {
2657     void* stackLimit;
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()));
2662 #else
2663     pthread_attr_t attr;
2664     size_t stackSize;
2665     int status;
2666
2667     pthread_t thread = pthread_self();
2668
2669     status = pthread_attr_init(&attr);
2670     _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
2671
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);
2676 #else
2677 #error Dont know how to get thread attributes on this platform!
2678 #endif
2679     _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
2680
2681     status = pthread_attr_getstack(&attr, &stackLimit, &stackSize);
2682     _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
2683
2684     status = pthread_attr_destroy(&attr);
2685     _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
2686 #endif
2687
2688     return stackLimit;
2689 }
2690
2691 // Get cached base address of this thread's stack
2692 // Can be called only for the current thread.
2693 void *
2694 CPalThread::GetCachedStackBase()
2695 {
2696     _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetStackBase called from foreign thread");
2697
2698     if (m_stackBase == NULL)
2699     {
2700         m_stackBase = GetStackBase();
2701     }
2702
2703     return m_stackBase;
2704 }
2705
2706 // Get cached limit address of this thread's stack.
2707 // Can be called only for the current thread.
2708 void *
2709 CPalThread::GetCachedStackLimit()
2710 {
2711     _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetCachedStackLimit called from foreign thread");
2712
2713     if (m_stackLimit == NULL)
2714     {
2715         m_stackLimit = GetStackLimit();
2716     }
2717
2718     return m_stackLimit;
2719 }
2720
2721 void *
2722 PALAPI
2723 PAL_GetStackBase()
2724 {
2725     CPalThread* thread = InternalGetCurrentThread();
2726     return thread->GetCachedStackBase();
2727 }
2728
2729 void *
2730 PALAPI
2731 PAL_GetStackLimit()
2732 {
2733     CPalThread* thread = InternalGetCurrentThread();
2734     return thread->GetCachedStackLimit();
2735 }
2736
2737 PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread);
2738
2739 /*++
2740 Function:
2741     PAL_SetActivationFunction
2742
2743     Register an activation function that gets called when an activation is injected
2744     into a thread.
2745
2746 Parameters:
2747     pActivationFunction - activation function
2748     pSafeActivationCheckFunction - function to check if an activation can be safely
2749                                    injected at a specified context
2750 Return value:
2751     None
2752 --*/
2753 PALIMPORT
2754 VOID
2755 PALAPI
2756 PAL_SetActivationFunction(
2757     IN PAL_ActivationFunction pActivationFunction,
2758     IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction)
2759 {
2760     g_activationFunction = pActivationFunction;
2761     g_safeActivationCheckFunction = pSafeActivationCheckFunction;
2762 }
2763
2764 /*++
2765 Function:
2766 PAL_InjectActivation
2767
2768 Interrupt the specified thread and have it call an activation function registered
2769 using the PAL_SetActivationFunction
2770
2771 Parameters:
2772 hThread            - handle of the target thread
2773
2774 Return:
2775 TRUE if it succeeded, FALSE otherwise.
2776 --*/
2777 BOOL
2778 PALAPI
2779 PAL_InjectActivation(
2780     IN HANDLE hThread)
2781 {
2782     PERF_ENTRY(PAL_InjectActivation);
2783     ENTRY("PAL_InjectActivation(hThread=%p)\n", hThread);
2784
2785     CPalThread *pCurrentThread;
2786     CPalThread *pTargetThread;
2787     IPalObject *pobjThread = NULL;
2788
2789     pCurrentThread = InternalGetCurrentThread();
2790
2791     PAL_ERROR palError = InternalGetThreadDataFromHandle(
2792         pCurrentThread,
2793         hThread,
2794         0,
2795         &pTargetThread,
2796         &pobjThread
2797         );
2798
2799     if (palError == NO_ERROR)
2800     {
2801         palError = InjectActivationInternal(pTargetThread);
2802     }
2803
2804     if (palError == NO_ERROR)
2805     {
2806         pCurrentThread->SetLastError(palError);
2807     }
2808
2809     if (pobjThread != NULL)
2810     {
2811         pobjThread->ReleaseReference(pCurrentThread);
2812     }
2813
2814     BOOL success = (palError == NO_ERROR);
2815     LOGEXIT("PAL_InjectActivation returns:d\n", success);
2816     PERF_EXIT(PAL_InjectActivation);
2817
2818     return success;
2819 }
2820
2821 #if HAVE_MACH_EXCEPTIONS
2822
2823 extern mach_port_t s_ExceptionPort;
2824
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)
2828 {
2829     exception_mask_t bmExceptionMask = (1 << eException);
2830     int idxHandler = GetIndexOfHandler(bmExceptionMask);
2831
2832     // Did we find a handler?
2833     if (idxHandler == -1)
2834         return false;
2835
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];
2841
2842     return true;
2843 }
2844
2845 // Look for a handler for the given exception within the given handler node. Return its index if successful or
2846 // -1 otherwise.
2847 int CorUnix::CThreadMachExceptionHandlers::GetIndexOfHandler(exception_mask_t bmExceptionMask)
2848 {
2849     // Check all handler entries for one handling the exception mask.
2850     for (mach_msg_type_number_t i = 0; i < m_nPorts; i++)
2851     {
2852         // Entry covers this exception type and the handler isn't null
2853         if (m_masks[i] & bmExceptionMask && m_handlers[i] != MACH_PORT_NULL)
2854         { 
2855             _ASSERTE(m_handlers[i] != s_ExceptionPort);
2856
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))
2860             {
2861                 // Got a matching entry.
2862                 return i;
2863             }
2864         }
2865     }
2866
2867     // Didn't find a handler.
2868     return -1;
2869 }
2870
2871 #endif // HAVE_MACH_EXCEPTIONS