Jack2 1.9.6

JackMachThread.cpp

00001 /*
00002 Copyright (C) 2001 Paul Davis
00003 Copyright (C) 2004-2008 Grame
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU Lesser General Public License as published by
00007 the Free Software Foundation; either version 2.1 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public License
00016 along with this program; if not, write to the Free Software 
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 
00019 */
00020 
00021 #include "JackMachThread.h"
00022 #include "JackError.h"
00023 
00024 namespace Jack
00025 {
00026 
00027 int JackMachThread::SetThreadToPriority(pthread_t thread, UInt32 inPriority, Boolean inIsFixed, UInt64 period, UInt64 computation, UInt64 constraint)
00028 {
00029     if (inPriority == 96) {
00030         // REAL-TIME / TIME-CONSTRAINT THREAD
00031         thread_time_constraint_policy_data_t    theTCPolicy;
00032 
00033         theTCPolicy.period = AudioConvertNanosToHostTime(period);
00034         theTCPolicy.computation = AudioConvertNanosToHostTime(computation);
00035         theTCPolicy.constraint = AudioConvertNanosToHostTime(constraint);
00036         theTCPolicy.preemptible = true;
00037         kern_return_t res = thread_policy_set(pthread_mach_thread_np(thread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) & theTCPolicy, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
00038         jack_log("JackMachThread::thread_policy_set res = %ld", res);
00039         return (res == KERN_SUCCESS) ? 0 : -1;
00040     } else {
00041         // OTHER THREADS
00042         thread_extended_policy_data_t theFixedPolicy;
00043         thread_precedence_policy_data_t thePrecedencePolicy;
00044         SInt32 relativePriority;
00045 
00046         // [1] SET FIXED / NOT FIXED
00047         theFixedPolicy.timeshare = !inIsFixed;
00048         thread_policy_set(pthread_mach_thread_np(thread), THREAD_EXTENDED_POLICY, (thread_policy_t)&theFixedPolicy, THREAD_EXTENDED_POLICY_COUNT);
00049 
00050         // [2] SET PRECEDENCE
00051         // N.B.: We expect that if thread A created thread B, and the program wishes to change
00052         // the priority of thread B, then the call to change the priority of thread B must be
00053         // made by thread A.
00054         // This assumption allows us to use pthread_self() to correctly calculate the priority
00055         // of the feeder thread (since precedency policy's importance is relative to the
00056         // spawning thread's priority.)
00057         relativePriority = inPriority - GetThreadSetPriority(pthread_self());
00058 
00059         thePrecedencePolicy.importance = relativePriority;
00060         kern_return_t res = thread_policy_set(pthread_mach_thread_np(thread), THREAD_PRECEDENCE_POLICY, (thread_policy_t) & thePrecedencePolicy, THREAD_PRECEDENCE_POLICY_COUNT);
00061         jack_log("JackMachThread::thread_policy_set res = %ld", res);
00062         return (res == KERN_SUCCESS) ? 0 : -1;
00063     }
00064 }
00065 
00066 // returns the thread's priority as it was last set by the API
00067 UInt32 JackMachThread::GetThreadSetPriority(pthread_t thread)
00068 {
00069     return GetThreadPriority(thread, THREAD_SET_PRIORITY);
00070 }
00071 
00072 // returns the thread's priority as it was last scheduled by the Kernel
00073 UInt32 JackMachThread::GetThreadScheduledPriority(pthread_t thread)
00074 {
00075     return GetThreadPriority(thread, THREAD_SCHEDULED_PRIORITY);
00076 }
00077 
00078 UInt32 JackMachThread::GetThreadPriority(pthread_t thread, int inWhichPriority)
00079 {
00080     thread_basic_info_data_t threadInfo;
00081     policy_info_data_t thePolicyInfo;
00082     unsigned int count;
00083 
00084     // get basic info
00085     count = THREAD_BASIC_INFO_COUNT;
00086     thread_info(pthread_mach_thread_np(thread), THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &count);
00087 
00088     switch (threadInfo.policy) {
00089         case POLICY_TIMESHARE:
00090             count = POLICY_TIMESHARE_INFO_COUNT;
00091             thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&(thePolicyInfo.ts), &count);
00092             if (inWhichPriority == THREAD_SCHEDULED_PRIORITY) {
00093                 return thePolicyInfo.ts.cur_priority;
00094             } else {
00095                 return thePolicyInfo.ts.base_priority;
00096             }
00097             break;
00098 
00099         case POLICY_FIFO:
00100             count = POLICY_FIFO_INFO_COUNT;
00101             thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_FIFO_INFO, (thread_info_t)&(thePolicyInfo.fifo), &count);
00102             if ( (thePolicyInfo.fifo.depressed) && (inWhichPriority == THREAD_SCHEDULED_PRIORITY) ) {
00103                 return thePolicyInfo.fifo.depress_priority;
00104             }
00105             return thePolicyInfo.fifo.base_priority;
00106             break;
00107 
00108         case POLICY_RR:
00109             count = POLICY_RR_INFO_COUNT;
00110             thread_info(pthread_mach_thread_np(thread), THREAD_SCHED_RR_INFO, (thread_info_t)&(thePolicyInfo.rr), &count);
00111             if ( (thePolicyInfo.rr.depressed) && (inWhichPriority == THREAD_SCHEDULED_PRIORITY) ) {
00112                 return thePolicyInfo.rr.depress_priority;
00113             }
00114             return thePolicyInfo.rr.base_priority;
00115             break;
00116     }
00117 
00118     return 0;
00119 }
00120 
00121 int JackMachThread::GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint)
00122 {
00123     thread_time_constraint_policy_data_t theTCPolicy;
00124     mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT;
00125     boolean_t get_default = false;
00126 
00127     kern_return_t res = thread_policy_get(pthread_mach_thread_np(thread),
00128                                           THREAD_TIME_CONSTRAINT_POLICY,
00129                                           (thread_policy_t) & theTCPolicy,
00130                                           &count,
00131                                           &get_default);
00132     if (res == KERN_SUCCESS) {
00133         *period = AudioConvertHostTimeToNanos(theTCPolicy.period);
00134         *computation = AudioConvertHostTimeToNanos(theTCPolicy.computation);
00135         *constraint = AudioConvertHostTimeToNanos(theTCPolicy.constraint);
00136         jack_log("JackMachThread::GetParams period = %ld computation = %ld constraint = %ld", long(*period / 1000.0f), long(*computation / 1000.0f), long(*constraint / 1000.0f));
00137         return 0;
00138     } else {
00139         return -1;
00140     }
00141 }
00142 
00143 int JackMachThread::Kill()
00144 {
00145     // pthread_cancel still not yet implemented in Darwin (TO CHECK ON TIGER)
00146     jack_log("JackMachThread::Kill");
00147     
00148     if (fThread != (pthread_t)NULL)  { // If thread has been started
00149         mach_port_t machThread = pthread_mach_thread_np(fThread);
00150         int res = (thread_terminate(machThread) == KERN_SUCCESS) ? 0 : -1;
00151         fThread = (pthread_t)NULL;
00152         return res;
00153     } else {
00154         return -1;
00155     }
00156 }
00157 
00158 int JackMachThread::AcquireRealTime()
00159 {
00160     jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld",
00161              long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000));
00162     return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPeriod, fComputation, fConstraint) : -1; 
00163 }
00164 
00165 int JackMachThread::AcquireSelfRealTime()
00166 {
00167     jack_log("JackMachThread::AcquireRealTime fPeriod = %ld fComputation = %ld fConstraint = %ld",
00168              long(fPeriod / 1000), long(fComputation / 1000), long(fConstraint / 1000));
00169     return AcquireRealTimeImp(pthread_self(), fPeriod, fComputation, fConstraint);
00170 }
00171 
00172 int JackMachThread::AcquireRealTime(int priority)
00173 {
00174     fPriority = priority;
00175     return AcquireRealTime();
00176 }
00177 
00178 int JackMachThread::AcquireSelfRealTime(int priority)
00179 {
00180     fPriority = priority;
00181     return AcquireSelfRealTime();
00182 }
00183 
00184 int JackMachThread::AcquireRealTimeImp(pthread_t thread, UInt64 period, UInt64 computation, UInt64 constraint)
00185 {
00186     SetThreadToPriority(thread, 96, true, period, computation, constraint);
00187     return 0;
00188 }
00189 
00190 int JackMachThread::DropRealTime()
00191 {
00192     return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1;
00193 }
00194 
00195 int JackMachThread::DropSelfRealTime()
00196 {
00197     return DropRealTimeImp(pthread_self());
00198 }
00199 
00200 int JackMachThread::DropRealTimeImp(pthread_t thread)
00201 {
00202     SetThreadToPriority(thread, 63, false, 0, 0, 0);
00203     return 0;
00204 }
00205 
00206 void JackMachThread::SetParams(UInt64 period, UInt64 computation, UInt64 constraint)
00207 {
00208     fPeriod = period;
00209     fComputation = computation;
00210     fConstraint = constraint;
00211 }
00212 
00213 } // end of namespace
00214