Jack2 1.9.6

JackPosixThread.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 "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 }