Jack2 1.9.10

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("JackPosixThread::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("JackPosixThread::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(jack_native_thread_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("JackPosixThread::StartImp : 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("JackPosixThread::StartImp : 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 != (jack_native_thread_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 = (jack_native_thread_t)NULL;
00162         return 0;
00163     } else {
00164         return -1;
00165     }
00166 }
00167 
00168 int JackPosixThread::Stop()
00169 {
00170     if (fThread != (jack_native_thread_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 = (jack_native_thread_t)NULL;
00176         return 0;
00177     } else {
00178         return -1;
00179     }
00180 }
00181 
00182 int JackPosixThread::KillImp(jack_native_thread_t thread)
00183 {
00184     if (thread != (jack_native_thread_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(jack_native_thread_t thread)
00196 {
00197     if (thread != (jack_native_thread_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 != (jack_native_thread_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(jack_native_thread_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     jack_log("JackPosixThread::AcquireRealTimeImp priority = %d", priority);
00236 
00237     if ((res = pthread_setschedparam(thread, JACK_SCHED_POLICY, &rtparam)) != 0) {
00238         jack_error("Cannot use real-time scheduling (RR/%d)"
00239                    "(%d: %s)", rtparam.sched_priority, res,
00240                    strerror(res));
00241         return -1;
00242     }
00243     return 0;
00244 }
00245 
00246 int JackPosixThread::DropRealTime()
00247 {
00248     return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1;
00249 }
00250 
00251 int JackPosixThread::DropSelfRealTime()
00252 {
00253     return DropRealTimeImp(pthread_self());
00254 }
00255 
00256 int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread)
00257 {
00258     struct sched_param rtparam;
00259     int res;
00260     memset(&rtparam, 0, sizeof(rtparam));
00261     rtparam.sched_priority = 0;
00262 
00263     if ((res = pthread_setschedparam(thread, SCHED_OTHER, &rtparam)) != 0) {
00264         jack_error("Cannot switch to normal scheduling priority(%s)", strerror(errno));
00265         return -1;
00266     }
00267     return 0;
00268 }
00269 
00270 jack_native_thread_t JackPosixThread::GetThreadID()
00271 {
00272     return fThread;
00273 }
00274 
00275 bool JackPosixThread::IsThread()
00276 {
00277     return pthread_self() == fThread;
00278 }
00279 
00280 void JackPosixThread::Terminate()
00281 {
00282     jack_log("JackPosixThread::Terminate");
00283     pthread_exit(0);
00284 }
00285 
00286 SERVER_EXPORT void ThreadExit()
00287 {
00288     jack_log("ThreadExit");
00289     pthread_exit(0);
00290 }
00291 
00292 } // end of namespace
00293 
00294 bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr)
00295 {
00296 #if defined(_POSIX_PRIORITY_SCHEDULING) && !defined(__APPLE__)
00297     int min, max;
00298 
00299     min = sched_get_priority_min(JACK_SCHED_POLICY);
00300     if (min == -1)
00301     {
00302         jack_error("sched_get_priority_min() failed.");
00303         return false;
00304     }
00305 
00306     max = sched_get_priority_max(JACK_SCHED_POLICY);
00307     if (max == -1)
00308     {
00309         jack_error("sched_get_priority_max() failed.");
00310         return false;
00311     }
00312 
00313     *min_ptr = min;
00314     *max_ptr = max;
00315 
00316     return true;
00317 #else
00318     return false;
00319 #endif
00320 }
00321 
00322 bool jack_tls_allocate_key(jack_tls_key *key_ptr)
00323 {
00324     int ret;
00325 
00326     ret = pthread_key_create(key_ptr, NULL);
00327     if (ret != 0)
00328     {
00329         jack_error("pthread_key_create() failed with error %d", ret);
00330         return false;
00331     }
00332 
00333     return true;
00334 }
00335 
00336 bool jack_tls_free_key(jack_tls_key key)
00337 {
00338     int ret;
00339 
00340     ret = pthread_key_delete(key);
00341     if (ret != 0)
00342     {
00343         jack_error("pthread_key_delete() failed with error %d", ret);
00344         return false;
00345     }
00346 
00347     return true;
00348 }
00349 
00350 bool jack_tls_set(jack_tls_key key, void *data_ptr)
00351 {
00352     int ret;
00353 
00354     ret = pthread_setspecific(key, (const void *)data_ptr);
00355     if (ret != 0)
00356     {
00357         jack_error("pthread_setspecific() failed with error %d", ret);
00358         return false;
00359     }
00360 
00361     return true;
00362 }
00363 
00364 void *jack_tls_get(jack_tls_key key)
00365 {
00366     return pthread_getspecific(key);
00367 }