Jamoma API  0.6.0.a19
CAPThread.cpp
1 /* Copyright © 2007 Apple Inc. All Rights Reserved.
2 
3  Disclaimer: IMPORTANT: This Apple software is supplied to you by
4  Apple Inc. ("Apple") in consideration of your agreement to the
5  following terms, and your use, installation, modification or
6  redistribution of this Apple software constitutes acceptance of these
7  terms. If you do not agree with these terms, please do not use,
8  install, modify or redistribute this Apple software.
9 
10  In consideration of your agreement to abide by the following terms, and
11  subject to these terms, Apple grants you a personal, non-exclusive
12  license, under Apple's copyrights in this original Apple software (the
13  "Apple Software"), to use, reproduce, modify and redistribute the Apple
14  Software, with or without modifications, in source and/or binary forms;
15  provided that if you redistribute the Apple Software in its entirety and
16  without modifications, you must retain this notice and the following
17  text and disclaimers in all such redistributions of the Apple Software.
18  Neither the name, trademarks, service marks or logos of Apple Inc.
19  may be used to endorse or promote products derived from the Apple
20  Software without specific prior written permission from Apple. Except
21  as expressly stated in this notice, no other rights or licenses, express
22  or implied, are granted by Apple herein, including but not limited to
23  any patent rights that may be infringed by your derivative works or by
24  other works in which the Apple Software may be incorporated.
25 
26  The Apple Software is provided by Apple on an "AS IS" basis. APPLE
27  MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
28  THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
29  FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
30  OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
31 
32  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
33  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
36  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
37  AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
38  STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
39  POSSIBILITY OF SUCH DAMAGE.
40 */
41 //=============================================================================
42 // Includes
43 //=============================================================================
44 
45 // Self Include
46 #include "CAPThread.h"
47 
48 // PublicUtility Includes
49 #include "CADebugMacros.h"
50 #include "CAException.h"
51 
52 // System Includes
53 #if TARGET_OS_MAC
54  #include <mach/mach.h>
55 #endif
56 
57 // Standard Library Includes
58 #include <stdio.h>
59 
60 //==================================================================================================
61 // CAPThread
62 //==================================================================================================
63 
64 // returns the thread's priority as it was last set by the API
65 #define CAPTHREAD_SET_PRIORITY 0
66 // returns the thread's priority as it was last scheduled by the Kernel
67 #define CAPTHREAD_SCHEDULED_PRIORITY 1
68 
69 //#define Log_SetPriority 1
70 
71 CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPriority, bool inFixedPriority, bool inAutoDelete)
72 :
73 #if TARGET_OS_MAC
74  mPThread(0),
75  mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)),
76 #elif TARGET_OS_WIN32
77  mThreadHandle(NULL),
78  mThreadID(0),
79 #endif
80  mThreadRoutine(inThreadRoutine),
81  mThreadParameter(inParameter),
82  mPriority(inPriority),
83  mPeriod(0),
84  mComputation(0),
85  mConstraint(0),
86  mIsPreemptible(true),
87  mTimeConstraintSet(false),
88  mFixedPriority(inFixedPriority),
89  mAutoDelete(inAutoDelete)
90 {
91 }
92 
93 CAPThread::CAPThread(ThreadRoutine inThreadRoutine, void* inParameter, UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible, bool inAutoDelete)
94 :
95 #if TARGET_OS_MAC
96  mPThread(0),
97  mSpawningThreadPriority(getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY)),
98 #elif TARGET_OS_WIN32
99  mThreadHandle(NULL),
100  mThreadID(0),
101 #endif
102  mThreadRoutine(inThreadRoutine),
103  mThreadParameter(inParameter),
104  mPriority(kDefaultThreadPriority),
105  mPeriod(inPeriod),
106  mComputation(inComputation),
107  mConstraint(inConstraint),
108  mIsPreemptible(inIsPreemptible),
109  mTimeConstraintSet(true),
110  mFixedPriority(false),
111  mAutoDelete(inAutoDelete)
112 {
113 }
114 
115 CAPThread::~CAPThread()
116 {
117 }
118 
119 UInt32 CAPThread::GetScheduledPriority()
120 {
121 #if TARGET_OS_MAC
122  return CAPThread::getScheduledPriority( mPThread, CAPTHREAD_SCHEDULED_PRIORITY );
123 #elif TARGET_OS_WIN32
124  UInt32 theAnswer = 0;
125  if(mThreadHandle != NULL)
126  {
127  theAnswer = GetThreadPriority(mThreadHandle);
128  }
129  return theAnswer;
130 #endif
131 }
132 
133 void CAPThread::SetPriority(UInt32 inPriority, bool inFixedPriority)
134 {
135  mPriority = inPriority;
136  mTimeConstraintSet = false;
137  mFixedPriority = inFixedPriority;
138 #if TARGET_OS_MAC
139  if(mPThread != 0)
140  {
141  kern_return_t theError = 0;
142 
143  // set whether or not this is a fixed priority thread
144  if (mFixedPriority)
145  {
146  thread_extended_policy_data_t theFixedPolicy = { false };
147  theError = thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
148  AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the fixed-priority policy");
149  }
150 
151  // set the thread's absolute priority which is relative to the priority on which thread_policy_set() is called
152  UInt32 theCurrentThreadPriority = getScheduledPriority(pthread_self(), CAPTHREAD_SET_PRIORITY);
153  thread_precedence_policy_data_t thePrecedencePolicy = { mPriority - theCurrentThreadPriority };
154  theError = thread_policy_set(pthread_mach_thread_np(mPThread), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
155  AssertNoKernelError(theError, "CAPThread::SetPriority: failed to set the precedence policy");
156 
157  #if Log_SetPriority
158  DebugMessageN4("CAPThread::SetPriority: requsted: %lu spawning: %lu current: %lu assigned: %d", mPriority, mSpawningThreadPriority, theCurrentThreadPriority, thePrecedencePolicy.importance);
159  #endif
160  }
161 #elif TARGET_OS_WIN32
162  if(mThreadHandle != NULL)
163  {
164  SetThreadPriority(mThreadHandle, mPriority);
165  }
166 #endif
167 }
168 
169 void CAPThread::SetTimeConstraints(UInt32 inPeriod, UInt32 inComputation, UInt32 inConstraint, bool inIsPreemptible)
170 {
171  mPeriod = inPeriod;
172  mComputation = inComputation;
173  mConstraint = inConstraint;
174  mIsPreemptible = inIsPreemptible;
175  mTimeConstraintSet = true;
176 #if TARGET_OS_MAC
177  if(mPThread != 0)
178  {
179  thread_time_constraint_policy_data_t thePolicy;
180  thePolicy.period = mPeriod;
181  thePolicy.computation = mComputation;
182  thePolicy.constraint = mConstraint;
183  thePolicy.preemptible = mIsPreemptible;
184  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");
185  }
186 #elif TARGET_OS_WIN32
187  if(mThreadHandle != NULL)
188  {
189  SetThreadPriority(mThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
190  }
191 #endif
192 }
193 
194 void CAPThread::Start()
195 {
196 #if TARGET_OS_MAC
197  Assert(mPThread == 0, "CAPThread::Start: can't start because the thread is already running");
198  if(mPThread == 0)
199  {
200  OSStatus theResult;
201  pthread_attr_t theThreadAttributes;
202 
203  theResult = pthread_attr_init(&theThreadAttributes);
204  ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: Thread attributes could not be created.");
205 
206  theResult = pthread_attr_setdetachstate(&theThreadAttributes, PTHREAD_CREATE_DETACHED);
207  ThrowIf(theResult != 0, CAException(theResult), "CAPThread::Start: A thread could not be created in the detached state.");
208 
209  theResult = pthread_create(&mPThread, &theThreadAttributes, (ThreadRoutine)CAPThread::Entry, this);
210  ThrowIf(theResult != 0 || !mPThread, CAException(theResult), "CAPThread::Start: Could not create a thread.");
211 
212  pthread_attr_destroy(&theThreadAttributes);
213 
214  }
215 #elif TARGET_OS_WIN32
216  Assert(mThreadID == 0, "CAPThread::Start: can't start because the thread is already running");
217  if(mThreadID == 0)
218  {
219  // clean up the existing thread handle
220  if(mThreadHandle != NULL)
221  {
222  CloseHandle(mThreadHandle);
223  mThreadHandle = NULL;
224  }
225 
226  // create a new thread
227  mThreadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Entry, this, 0, &mThreadID);
228  ThrowIf(mThreadHandle == NULL, CAException(GetLastError()), "CAPThread::Start: Could not create a thread.");
229  }
230 #endif
231 }
232 
233 #if TARGET_OS_MAC
234 
235 void* CAPThread::Entry(CAPThread* inCAPThread)
236 {
237  void* theAnswer = NULL;
238 
239  try
240  {
241  if(inCAPThread->mTimeConstraintSet)
242  {
243  inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible);
244  }
245  else
246  {
247  inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority);
248  }
249 
250  if(inCAPThread->mThreadRoutine != NULL)
251  {
252  theAnswer = inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter);
253  }
254  }
255  catch (...)
256  {
257  // what should be done here?
258  }
259  inCAPThread->mPThread = 0;
260  if (inCAPThread->mAutoDelete)
261  delete inCAPThread;
262  return theAnswer;
263 }
264 
265 UInt32 CAPThread::getScheduledPriority(pthread_t inThread, int inPriorityKind)
266 {
267  thread_basic_info_data_t threadInfo;
268  policy_info_data_t thePolicyInfo;
269  unsigned int count;
270 
271  if (inThread == NULL)
272  return 0;
273 
274  // get basic info
275  count = THREAD_BASIC_INFO_COUNT;
276  thread_info (pthread_mach_thread_np (inThread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count);
277 
278  switch (threadInfo.policy) {
279  case POLICY_TIMESHARE:
280  count = POLICY_TIMESHARE_INFO_COUNT;
281  thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count);
282  if (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) {
283  return thePolicyInfo.ts.cur_priority;
284  }
285  return thePolicyInfo.ts.base_priority;
286  break;
287 
288  case POLICY_FIFO:
289  count = POLICY_FIFO_INFO_COUNT;
290  thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count);
291  if ( (thePolicyInfo.fifo.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) {
292  return thePolicyInfo.fifo.depress_priority;
293  }
294  return thePolicyInfo.fifo.base_priority;
295  break;
296 
297  case POLICY_RR:
298  count = POLICY_RR_INFO_COUNT;
299  thread_info(pthread_mach_thread_np (inThread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count);
300  if ( (thePolicyInfo.rr.depressed) && (inPriorityKind == CAPTHREAD_SCHEDULED_PRIORITY) ) {
301  return thePolicyInfo.rr.depress_priority;
302  }
303  return thePolicyInfo.rr.base_priority;
304  break;
305  }
306 
307  return 0;
308 }
309 
310 #elif TARGET_OS_WIN32
311 
312 UInt32 WINAPI CAPThread::Entry(CAPThread* inCAPThread)
313 {
314  UInt32 theAnswer = 0;
315 
316  try
317  {
318  if(inCAPThread->mTimeConstraintSet)
319  {
320  inCAPThread->SetTimeConstraints(inCAPThread->mPeriod, inCAPThread->mComputation, inCAPThread->mConstraint, inCAPThread->mIsPreemptible);
321  }
322  else
323  {
324  inCAPThread->SetPriority(inCAPThread->mPriority, inCAPThread->mFixedPriority);
325  }
326 
327  if(inCAPThread->mThreadRoutine != NULL)
328  {
329  theAnswer = reinterpret_cast<UInt32>(inCAPThread->mThreadRoutine(inCAPThread->mThreadParameter));
330  }
331  inCAPThread->mThreadID = 0;
332  }
333  catch (...)
334  {
335  // what should be done here?
336  }
337  CloseHandle(inCAPThread->mThreadHandle);
338  inCAPThread->mThreadHandle = NULL;
339  if (inCAPThread->mAutoDelete)
340  delete inCAPThread;
341  return theAnswer;
342 }
343 
344 extern "C"
345 Boolean CompareAndSwap(UInt32 inOldValue, UInt32 inNewValue, UInt32* inOldValuePtr)
346 {
347  return InterlockedCompareExchange((volatile LONG*)inOldValuePtr, inNewValue, inOldValue) == inOldValue;
348 }
349 
350 #endif
351 
352 #if CoreAudio_Debug
353 void CAPThread::DebugPriority(const char *label)
354 {
355 #if !TARGET_OS_WIN32
356  if (mTimeConstraintSet)
357  printf("CAPThread::%s %p: pri=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
358  (int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
359  else
360  printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
361  (int)mSpawningThreadPriority, (mPThread != NULL) ? (int)GetScheduledPriority() : -1);
362 #else
363  if (mTimeConstraintSet)
364  {
365  printf("CAPThread::%s %p: pri=<time constraint>, spawning pri=%d, scheduled pri=%d\n", label, this,
366  (int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
367  }
368  else
369  {
370  printf("CAPThread::%s %p: pri=%d%s, spawning pri=%d, scheduled pri=%d\n", label, this, (int)mPriority, mFixedPriority ? " fixed" : "",
371  (int)mPriority, (mThreadHandle != NULL) ? (int)GetScheduledPriority() : -1);
372  }
373 #endif
374 }
375 #endif