Jack2 1.9.6
|
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 "JackPosixThread.h" 00022 #include "JackError.h" 00023 #include "JackTime.h" 00024 #include "JackGlobals.h" 00025 #include <string.h> // for memset 00026 #include <unistd.h> // for _POSIX_PRIORITY_SCHEDULING check 00027 00028 //#define JACK_SCHED_POLICY SCHED_RR 00029 #define JACK_SCHED_POLICY SCHED_FIFO 00030 00031 namespace Jack 00032 { 00033 00034 void* JackPosixThread::ThreadHandler(void* arg) 00035 { 00036 JackPosixThread* obj = (JackPosixThread*)arg; 00037 JackRunnableInterface* runnable = obj->fRunnable; 00038 int err; 00039 00040 if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) { 00041 jack_error("pthread_setcanceltype err = %s", strerror(err)); 00042 } 00043 00044 // Signal creation thread when started with StartSync 00045 jack_log("ThreadHandler: start"); 00046 obj->fStatus = kIniting; 00047 00048 // Call Init method 00049 if (!runnable->Init()) { 00050 jack_error("Thread init fails: thread quits"); 00051 return 0; 00052 } 00053 00054 obj->fStatus = kRunning; 00055 00056 // If Init succeed, start the thread loop 00057 bool res = true; 00058 while (obj->fStatus == kRunning && res) { 00059 res = runnable->Execute(); 00060 } 00061 00062 jack_log("ThreadHandler: exit"); 00063 pthread_exit(0); 00064 return 0; // never reached 00065 } 00066 00067 int JackPosixThread::Start() 00068 { 00069 fStatus = kStarting; 00070 00071 // Check if the thread was correctly started 00072 if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { 00073 fStatus = kIdle; 00074 return -1; 00075 } else { 00076 return 0; 00077 } 00078 } 00079 00080 int JackPosixThread::StartSync() 00081 { 00082 fStatus = kStarting; 00083 00084 if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) { 00085 fStatus = kIdle; 00086 return -1; 00087 } else { 00088 int count = 0; 00089 while (fStatus == kStarting && ++count < 1000) { 00090 JackSleep(1000); 00091 } 00092 return (count == 1000) ? -1 : 0; 00093 } 00094 } 00095 00096 int JackPosixThread::StartImp(pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg) 00097 { 00098 pthread_attr_t attributes; 00099 struct sched_param rt_param; 00100 pthread_attr_init(&attributes); 00101 int res; 00102 00103 if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) { 00104 jack_error("Cannot request joinable thread creation for thread res = %d", res); 00105 return -1; 00106 } 00107 00108 if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) { 00109 jack_error("Cannot set scheduling scope for thread res = %d", res); 00110 return -1; 00111 } 00112 00113 if (realtime) { 00114 00115 jack_log("Create RT thread"); 00116 00117 if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) { 00118 jack_error("Cannot request explicit scheduling for RT thread res = %d", res); 00119 return -1; 00120 } 00121 00122 if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) { 00123 jack_error("Cannot set RR scheduling class for RT thread res = %d", res); 00124 return -1; 00125 } 00126 00127 memset(&rt_param, 0, sizeof(rt_param)); 00128 rt_param.sched_priority = priority; 00129 00130 if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) { 00131 jack_error("Cannot set scheduling priority for RT thread res = %d", res); 00132 return -1; 00133 } 00134 00135 } else { 00136 jack_log("Create non RT thread"); 00137 } 00138 00139 if ((res = pthread_attr_setstacksize(&attributes, THREAD_STACK))) { 00140 jack_error("Cannot set thread stack size res = %d", res); 00141 return -1; 00142 } 00143 00144 if ((res = JackGlobals::fJackThreadCreator(thread, &attributes, start_routine, arg))) { 00145 jack_error("Cannot create thread res = %d", res); 00146 return -1; 00147 } 00148 00149 pthread_attr_destroy(&attributes); 00150 return 0; 00151 } 00152 00153 int JackPosixThread::Kill() 00154 { 00155 if (fThread != (pthread_t)NULL) { // If thread has been started 00156 jack_log("JackPosixThread::Kill"); 00157 void* status; 00158 pthread_cancel(fThread); 00159 pthread_join(fThread, &status); 00160 fStatus = kIdle; 00161 fThread = (pthread_t)NULL; 00162 return 0; 00163 } else { 00164 return -1; 00165 } 00166 } 00167 00168 int JackPosixThread::Stop() 00169 { 00170 if (fThread != (pthread_t)NULL) { // If thread has been started 00171 jack_log("JackPosixThread::Stop"); 00172 void* status; 00173 fStatus = kIdle; // Request for the thread to stop 00174 pthread_join(fThread, &status); 00175 fThread = (pthread_t)NULL; 00176 return 0; 00177 } else { 00178 return -1; 00179 } 00180 } 00181 00182 int JackPosixThread::KillImp(pthread_t thread) 00183 { 00184 if (thread != (pthread_t)NULL) { // If thread has been started 00185 jack_log("JackPosixThread::Kill"); 00186 void* status; 00187 pthread_cancel(thread); 00188 pthread_join(thread, &status); 00189 return 0; 00190 } else { 00191 return -1; 00192 } 00193 } 00194 00195 int JackPosixThread::StopImp(pthread_t thread) 00196 { 00197 if (thread != (pthread_t)NULL) { // If thread has been started 00198 jack_log("JackPosixThread::Stop"); 00199 void* status; 00200 pthread_join(thread, &status); 00201 return 0; 00202 } else { 00203 return -1; 00204 } 00205 } 00206 00207 int JackPosixThread::AcquireRealTime() 00208 { 00209 return (fThread != (pthread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1; 00210 } 00211 00212 int JackPosixThread::AcquireSelfRealTime() 00213 { 00214 return AcquireRealTimeImp(pthread_self(), fPriority); 00215 } 00216 00217 int JackPosixThread::AcquireRealTime(int priority) 00218 { 00219 fPriority = priority; 00220 return AcquireRealTime(); 00221 } 00222 00223 int JackPosixThread::AcquireSelfRealTime(int priority) 00224 { 00225 fPriority = priority; 00226 return AcquireSelfRealTime(); 00227 } 00228 int JackPosixThread::AcquireRealTimeImp(pthread_t thread, int priority) 00229 { 00230 struct sched_param rtparam; 00231 int res; 00232 memset(&rtparam, 0, sizeof(rtparam)); 00233 rtparam.sched_priority = priority; 00234 00235 if ((res = pthread_setschedparam(thread, JACK_SCHED_POLICY, &rtparam)) != 0) { 00236 jack_error("Cannot use real-time scheduling (RR/%d)" 00237 "(%d: %s)", rtparam.sched_priority, res, 00238 strerror(res)); 00239 return -1; 00240 } 00241 return 0; 00242 } 00243 00244 int JackPosixThread::DropRealTime() 00245 { 00246 return (fThread != (pthread_t)NULL) ? DropRealTimeImp(fThread) : -1; 00247 } 00248 00249 int JackPosixThread::DropSelfRealTime() 00250 { 00251 return DropRealTimeImp(pthread_self()); 00252 } 00253 00254 int JackPosixThread::DropRealTimeImp(pthread_t thread) 00255 { 00256 struct sched_param rtparam; 00257 int res; 00258 memset(&rtparam, 0, sizeof(rtparam)); 00259 rtparam.sched_priority = 0; 00260 00261 if ((res = pthread_setschedparam(thread, SCHED_OTHER, &rtparam)) != 0) { 00262 jack_error("Cannot switch to normal scheduling priority(%s)", strerror(errno)); 00263 return -1; 00264 } 00265 return 0; 00266 } 00267 00268 pthread_t JackPosixThread::GetThreadID() 00269 { 00270 return fThread; 00271 } 00272 00273 void JackPosixThread::Terminate() 00274 { 00275 jack_log("JackPosixThread::Terminate"); 00276 pthread_exit(0); 00277 } 00278 00279 SERVER_EXPORT void ThreadExit() 00280 { 00281 jack_log("ThreadExit"); 00282 pthread_exit(0); 00283 } 00284 00285 } // end of namespace 00286 00287 bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr) 00288 { 00289 #if defined(_POSIX_PRIORITY_SCHEDULING) && !defined(__APPLE__) 00290 int min, max; 00291 00292 min = sched_get_priority_min(JACK_SCHED_POLICY); 00293 if (min == -1) 00294 { 00295 jack_error("sched_get_priority_min() failed."); 00296 return false; 00297 } 00298 00299 max = sched_get_priority_max(JACK_SCHED_POLICY); 00300 if (max == -1) 00301 { 00302 jack_error("sched_get_priority_max() failed."); 00303 return false; 00304 } 00305 00306 *min_ptr = min; 00307 *max_ptr = max; 00308 00309 return true; 00310 #else 00311 return false; 00312 #endif 00313 } 00314 00315 bool jack_tls_allocate_key(jack_tls_key *key_ptr) 00316 { 00317 int ret; 00318 00319 ret = pthread_key_create(key_ptr, NULL); 00320 if (ret != 0) 00321 { 00322 jack_error("pthread_key_create() failed with error %d", ret); 00323 return false; 00324 } 00325 00326 return true; 00327 } 00328 00329 bool jack_tls_free_key(jack_tls_key key) 00330 { 00331 int ret; 00332 00333 ret = pthread_key_delete(key); 00334 if (ret != 0) 00335 { 00336 jack_error("pthread_key_delete() failed with error %d", ret); 00337 return false; 00338 } 00339 00340 return true; 00341 } 00342 00343 bool jack_tls_set(jack_tls_key key, void *data_ptr) 00344 { 00345 int ret; 00346 00347 ret = pthread_setspecific(key, (const void *)data_ptr); 00348 if (ret != 0) 00349 { 00350 jack_error("pthread_setspecific() failed with error %d", ret); 00351 return false; 00352 } 00353 00354 return true; 00355 } 00356 00357 void *jack_tls_get(jack_tls_key key) 00358 { 00359 return pthread_getspecific(key); 00360 }