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