/*============================================================================= CAPThread.cp $Log: CAPThread.cpp,v $ Revision 1.10 2005/02/24 02:26:35 dwyatt clear mPThread at the end of Entry even if there was an exception Revision 1.9 2004/09/30 21:03:40 jcm10 add a definition for CompareAndSwap on Windows Revision 1.8 2004/08/26 08:13:33 jcm10 finish bring up on Windows Revision 1.7 2004/08/26 04:42:02 jcm10 add initial Windows support Revision 1.6 2004/08/23 06:23:25 jcm10 make it build on Windows Revision 1.5 2004/07/17 00:13:50 asynth remove printfs Revision 1.4 2004/07/16 23:43:06 asynth set priority in the child thread Revision 1.3 2004/03/02 22:13:38 dwyatt add option to set fixed priority Revision 1.2 2004/03/02 20:29:25 dwyatt Add AssertNoError on calls to thread_policy_set Revision 1.1 2003/11/22 00:07:44 dwyatt initial checkin as .cpp Revision 1.5 2002/09/17 18:55:51 luke [2999188] fixed SetPriority(...) mechanism to work with new Mach API's. Also added call to get current scheduled priority of thread. Revision 1.4 2002/05/22 00:52:20 jcm10 clean up the usage of the mach thread policy APIs Revision 1.3 2002/05/18 01:14:02 bills back out mistaken commit Revision 1.2 2002/05/18 01:06:09 bills moved files to public utils Revision 1.1 2002/03/01 01:52:40 jcm10 moved here from ../Utility Revision 1.11 2002/02/28 23:24:29 jcm10 added the CA prefix to DebugMacros and LogMacros for more consistency Revision 1.10 2002/02/14 23:30:32 jcm10 clean up for gcc3 Revision 1.9 2001/11/15 02:05:18 jcm10 add an extern "C" around mach includes to make cpp-precomp happy Revision 1.8 2001/08/24 18:40:39 jcm10 revamp the implementation to better reflect how mach works Revision 1.7 2001/01/23 01:14:01 jcm10 in the time constraint methods, don't touch the thread unless it is actually there Revision 1.6 2001/01/16 22:23:57 jcm10 support the time constraint thread scheduling policy Revision 1.5 2000/12/08 22:09:11 jcm10 [2579498] include instead of the actual mach headers Revision 1.4 2000/09/13 02:28:49 jcm10 make it build again Revision 1.3 2000/09/12 23:14:46 jcm10 add SetSchedulingPolicy and use it Revision 1.2 2000/08/25 01:07:26 jcm10 update things to build the XFiles and prune the CoreAudio target to just the code necessary to run it Revision 1.1 2000/08/24 23:36:17 jcm10 first checked in Revision 0.0 2000/01/01 12:34:56 jcm10 created $NoKeywords: $ =============================================================================*/ //============================================================================= // Includes //============================================================================= // Self Include #include "CAPThread.h" // PublicUtility Includes #include "CADebugMacros.h" #include "CAException.h" // System Includes #if TARGET_OS_MAC #include #endif // Standard Library Includes #include //================================================================================================== // CAPThread //================================================================================================== // returns the thread's priority as it was last set by the API #define CAPTHREAD_SET_PRIORITY 0 // returns the thread's priority as it was last scheduled by the Kernel #define CAPTHREAD_SCHEDULED_PRIORITY 1 CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority, bool inFixedPriority) : #if TARGET_OS_MAC mPThread(0), mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), #elif TARGET_OS_WIN32 mThreadHandle(NULL), mThreadID(0), #endif mThreadRoutine(inThreadRoutine), mThreadParameter(inParameter), mPriority(inPriority), mPeriod(0), mComputation(0), mConstraint(0), mIsPreemptible(true), mTimeConstraintSet(false), mFixedPriority(inFixedPriority) { } CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible) : #if TARGET_OS_MAC mPThread(0), mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)), #elif TARGET_OS_WIN32 mThreadHandle(NULL), mThreadID(0), #endif mThreadRoutine(inThreadRoutine), mThreadParameter(inParameter), mPriority(kDefaultThreadPriority), mPeriod(inPeriod), mComputation(inComputation), mConstraint(inConstraint), mIsPreemptible(inIsPreemptible), mTimeConstraintSet(true), mFixedPriority(false) { } CAPThread::~CAPThread() { } UInt32 CAPThread::GetScheduledPriority() { #if TARGET_OS_MAC return CAPThread::getScheduledPriority( mPThread, CAPTHREAD_SCHEDULED_PRIORITY ); #elif TARGET_OS_WIN32 UInt32 theAnswer = 0; if(mThreadHandle != NULL) { theAnswer = GetThreadPriority(mThreadHandle); } return theAnswer; #endif } void CAPThread::SetPriority(UInt32 inPriority, bool inFixedPriority) { mPriority = inPriority; mTimeConstraintSet = false; mFixedPriority = inFixedPriority; #if TARGET_OS_MAC if(mPThread != 0) { if (mFixedPriority) { thread_extended_policy_data_t theFixedPolicy; theFixedPolicy.timeshare = false; // set to true for a non-fixed thread AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT), "CAPThread::SetPriority: failed to set the fixed-priority policy"); } // We keep a reference to the spawning thread's priority around (initialized in the constructor), // and set the importance of the child thread relative to the spawning thread's priority. thread_precedence_policy_data_t thePrecedencePolicy; thePrecedencePolicy.importance = mPriority - mSpawningThreadPriority; AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT), "CAPThread::SetPriority: failed to set the precedence policy"); } #elif TARGET_OS_WIN32 if(mThreadHandle != NULL) { SetThreadPriority(mThreadHandle, mPriority); } #endif } void CAPThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible) { mPeriod = inPeriod; mComputation = inComputation; mConstraint = inConstraint; mIsPreemptible = inIsPreemptible; mTimeConstraintSet = true; #if TARGET_OS_MAC if(mPThread != 0) { thread_time_constraint_policy_data_t thePolicy; thePolicy.period = mPeriod; thePolicy.computation = mComputation; thePolicy.constraint = mConstraint; thePolicy.preemptible = mIsPreemptible; AssertNoError(thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&thePolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT), "CAPThread::SetTimeConstraints: thread_policy_set failed"); } #elif TARGET_OS_WIN32 if(mThreadHandle != NULL) { SetThreadPriority(mThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); } #endif } void CAPThread::Start() { #if TARGET_OS_MAC if(mPThread == 0) { OSStatus theResult; pthread_attr_t theThreadAttributes; theResult = pthread_attr_init(&theThreadAttributes); ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: Thread attributes could not be created."); theResult = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED); ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: A thread could not be created in the detached state."); theResult = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)CAPThread::Entry, this); ThrowIf(theResult != 0 || !mPThread, CAException(theResult), "CAPThread::Start: Could not create a thread."); pthread_attr_destroy(&theThreadAttributes); } #elif TARGET_OS_WIN32 if(mThreadID == 0) { // clean up the existing thread handle if(mThreadHandle != NULL) { CloseHandle(mThreadHandle); mThreadHandle = NULL; } // create a new thread mThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Entry, this, 0, &mThreadID); ThrowIf(mThreadHandle == NULL, CAException(GetLastError()), "CAPThread::Start: Could not create a thread."); } #endif } #if TARGET_OS_MAC void* CAPThread::Entry(CAPThread* inCAPThread) { void* theAnswer = NULL; try { if(inCAPThread->mTimeConstraintSet) { inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); } else { inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); } if(inCAPThread->mThreadRoutine != NULL) { theAnswer = inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter); } } catch (...) { // what should be done here? } inCAPThread->mPThread = 0; return theAnswer; } UInt32 CAPThread::getScheduledPriority(pthread_t inThread, int inPriorityKind) { thread_basic_info_data_t threadInfo; policy_info_data_t thePolicyInfo; unsigned int count; if (inThread == NULL) return 0; // get basic info count = THREAD_BASIC_INFO_COUNT; thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count); switch (threadInfo.policy) { case POLICY_TIMESHARE: count = POLICY_TIMESHARE_INFO_COUNT; thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count); if (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) { return thePolicyInfo.ts.cur_priority; } return thePolicyInfo.ts.base_priority; break; case POLICY_FIFO: count = POLICY_FIFO_INFO_COUNT; thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count); if ( (thePolicyInfo.fifo.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { return thePolicyInfo.fifo.depress_priority; } return thePolicyInfo.fifo.base_priority; break; case POLICY_RR: count = POLICY_RR_INFO_COUNT; thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count); if ( (thePolicyInfo.rr.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) { return thePolicyInfo.rr.depress_priority; } return thePolicyInfo.rr.base_priority; break; } return 0; } #elif TARGET_OS_WIN32 UInt32 WINAPI CAPThread::Entry(CAPThread* inCAPThread) { UInt32 theAnswer = 0; try { if(inCAPThread->mTimeConstraintSet) { inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible); } else { inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority); } if(inCAPThread->mThreadRoutine != NULL) { theAnswer = reinterpret_cast(inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter)); } inCAPThread->mThreadID = 0; } catch (...) { // what should be done here? } return theAnswer; } // a definition of this function here for now extern "C" Boolean CompareAndSwap(UInt32 inOldValue, UInt32 inNewValue, UInt32* inOldValuePtr) { return InterlockedCompareExchange((volatile LONG*)inOldValuePtr, inNewValue, inOldValue) == inOldValue; } #endif