Jack2  1.9.9
JackPosixThread.cpp
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 */
20 
21 #include "JackPosixThread.h"
22 #include "JackError.h"
23 #include "JackTime.h"
24 #include "JackGlobals.h"
25 #include <string.h> // for memset
26 #include <unistd.h> // for _POSIX_PRIORITY_SCHEDULING check
27 
28 //#define JACK_SCHED_POLICY SCHED_RR
29 #define JACK_SCHED_POLICY SCHED_FIFO
30 
31 namespace Jack
32 {
33 
34 void* JackPosixThread::ThreadHandler(void* arg)
35 {
36  JackPosixThread* obj = (JackPosixThread*)arg;
37  JackRunnableInterface* runnable = obj->fRunnable;
38  int err;
39 
40  if ((err = pthread_setcanceltype(obj->fCancellation, NULL)) != 0) {
41  jack_error("pthread_setcanceltype err = %s", strerror(err));
42  }
43 
44  // Signal creation thread when started with StartSync
45  jack_log("JackPosixThread::ThreadHandler : start");
46  obj->fStatus = kIniting;
47 
48  // Call Init method
49  if (!runnable->Init()) {
50  jack_error("Thread init fails: thread quits");
51  return 0;
52  }
53 
54  obj->fStatus = kRunning;
55 
56  // If Init succeed, start the thread loop
57  bool res = true;
58  while (obj->fStatus == kRunning && res) {
59  res = runnable->Execute();
60  }
61 
62  jack_log("JackPosixThread::ThreadHandler : exit");
63  pthread_exit(0);
64  return 0; // never reached
65 }
66 
67 int JackPosixThread::Start()
68 {
69  fStatus = kStarting;
70 
71  // Check if the thread was correctly started
72  if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) {
73  fStatus = kIdle;
74  return -1;
75  } else {
76  return 0;
77  }
78 }
79 
80 int JackPosixThread::StartSync()
81 {
82  fStatus = kStarting;
83 
84  if (StartImp(&fThread, fPriority, fRealTime, ThreadHandler, this) < 0) {
85  fStatus = kIdle;
86  return -1;
87  } else {
88  int count = 0;
89  while (fStatus == kStarting && ++count < 1000) {
90  JackSleep(1000);
91  }
92  return (count == 1000) ? -1 : 0;
93  }
94 }
95 
96 int JackPosixThread::StartImp(jack_native_thread_t* thread, int priority, int realtime, void*(*start_routine)(void*), void* arg)
97 {
98  pthread_attr_t attributes;
99  struct sched_param rt_param;
100  pthread_attr_init(&attributes);
101  int res;
102 
103  if ((res = pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_JOINABLE))) {
104  jack_error("Cannot request joinable thread creation for thread res = %d", res);
105  return -1;
106  }
107 
108  if ((res = pthread_attr_setscope(&attributes, PTHREAD_SCOPE_SYSTEM))) {
109  jack_error("Cannot set scheduling scope for thread res = %d", res);
110  return -1;
111  }
112 
113  if (realtime) {
114 
115  jack_log("JackPosixThread::StartImp : create RT thread");
116 
117  if ((res = pthread_attr_setinheritsched(&attributes, PTHREAD_EXPLICIT_SCHED))) {
118  jack_error("Cannot request explicit scheduling for RT thread res = %d", res);
119  return -1;
120  }
121 
122  if ((res = pthread_attr_setschedpolicy(&attributes, JACK_SCHED_POLICY))) {
123  jack_error("Cannot set RR scheduling class for RT thread res = %d", res);
124  return -1;
125  }
126 
127  memset(&rt_param, 0, sizeof(rt_param));
128  rt_param.sched_priority = priority;
129 
130  if ((res = pthread_attr_setschedparam(&attributes, &rt_param))) {
131  jack_error("Cannot set scheduling priority for RT thread res = %d", res);
132  return -1;
133  }
134 
135  } else {
136  jack_log("JackPosixThread::StartImp : create non RT thread");
137  }
138 
139  if ((res = pthread_attr_setstacksize(&attributes, THREAD_STACK))) {
140  jack_error("Cannot set thread stack size res = %d", res);
141  return -1;
142  }
143 
144  if ((res = JackGlobals::fJackThreadCreator(thread, &attributes, start_routine, arg))) {
145  jack_error("Cannot create thread res = %d", res);
146  return -1;
147  }
148 
149  pthread_attr_destroy(&attributes);
150  return 0;
151 }
152 
153 int JackPosixThread::Kill()
154 {
155  if (fThread != (jack_native_thread_t)NULL) { // If thread has been started
156  jack_log("JackPosixThread::Kill");
157  void* status;
158  pthread_cancel(fThread);
159  pthread_join(fThread, &status);
160  fStatus = kIdle;
161  fThread = (jack_native_thread_t)NULL;
162  return 0;
163  } else {
164  return -1;
165  }
166 }
167 
168 int JackPosixThread::Stop()
169 {
170  if (fThread != (jack_native_thread_t)NULL) { // If thread has been started
171  jack_log("JackPosixThread::Stop");
172  void* status;
173  fStatus = kIdle; // Request for the thread to stop
174  pthread_join(fThread, &status);
175  fThread = (jack_native_thread_t)NULL;
176  return 0;
177  } else {
178  return -1;
179  }
180 }
181 
182 int JackPosixThread::KillImp(jack_native_thread_t thread)
183 {
184  if (thread != (jack_native_thread_t)NULL) { // If thread has been started
185  jack_log("JackPosixThread::Kill");
186  void* status;
187  pthread_cancel(thread);
188  pthread_join(thread, &status);
189  return 0;
190  } else {
191  return -1;
192  }
193 }
194 
195 int JackPosixThread::StopImp(jack_native_thread_t thread)
196 {
197  if (thread != (jack_native_thread_t)NULL) { // If thread has been started
198  jack_log("JackPosixThread::Stop");
199  void* status;
200  pthread_join(thread, &status);
201  return 0;
202  } else {
203  return -1;
204  }
205 }
206 
207 int JackPosixThread::AcquireRealTime()
208 {
209  return (fThread != (jack_native_thread_t)NULL) ? AcquireRealTimeImp(fThread, fPriority) : -1;
210 }
211 
212 int JackPosixThread::AcquireSelfRealTime()
213 {
214  return AcquireRealTimeImp(pthread_self(), fPriority);
215 }
216 
217 int JackPosixThread::AcquireRealTime(int priority)
218 {
219  fPriority = priority;
220  return AcquireRealTime();
221 }
222 
223 int JackPosixThread::AcquireSelfRealTime(int priority)
224 {
225  fPriority = priority;
226  return AcquireSelfRealTime();
227 }
228 int JackPosixThread::AcquireRealTimeImp(jack_native_thread_t thread, int priority)
229 {
230  struct sched_param rtparam;
231  int res;
232  memset(&rtparam, 0, sizeof(rtparam));
233  rtparam.sched_priority = priority;
234 
235  jack_log("JackPosixThread::AcquireRealTimeImp priority = %d", priority);
236 
237  if ((res = pthread_setschedparam(thread, JACK_SCHED_POLICY, &rtparam)) != 0) {
238  jack_error("Cannot use real-time scheduling (RR/%d)"
239  "(%d: %s)", rtparam.sched_priority, res,
240  strerror(res));
241  return -1;
242  }
243  return 0;
244 }
245 
246 int JackPosixThread::DropRealTime()
247 {
248  return (fThread != (jack_native_thread_t)NULL) ? DropRealTimeImp(fThread) : -1;
249 }
250 
251 int JackPosixThread::DropSelfRealTime()
252 {
253  return DropRealTimeImp(pthread_self());
254 }
255 
256 int JackPosixThread::DropRealTimeImp(jack_native_thread_t thread)
257 {
258  struct sched_param rtparam;
259  int res;
260  memset(&rtparam, 0, sizeof(rtparam));
261  rtparam.sched_priority = 0;
262 
263  if ((res = pthread_setschedparam(thread, SCHED_OTHER, &rtparam)) != 0) {
264  jack_error("Cannot switch to normal scheduling priority(%s)", strerror(errno));
265  return -1;
266  }
267  return 0;
268 }
269 
270 jack_native_thread_t JackPosixThread::GetThreadID()
271 {
272  return fThread;
273 }
274 
275 bool JackPosixThread::IsThread()
276 {
277  return pthread_self() == fThread;
278 }
279 
280 void JackPosixThread::Terminate()
281 {
282  jack_log("JackPosixThread::Terminate");
283  pthread_exit(0);
284 }
285 
286 SERVER_EXPORT void ThreadExit()
287 {
288  jack_log("ThreadExit");
289  pthread_exit(0);
290 }
291 
292 } // end of namespace
293 
294 bool jack_get_thread_realtime_priority_range(int * min_ptr, int * max_ptr)
295 {
296 #if defined(_POSIX_PRIORITY_SCHEDULING) && !defined(__APPLE__)
297  int min, max;
298 
299  min = sched_get_priority_min(JACK_SCHED_POLICY);
300  if (min == -1)
301  {
302  jack_error("sched_get_priority_min() failed.");
303  return false;
304  }
305 
306  max = sched_get_priority_max(JACK_SCHED_POLICY);
307  if (max == -1)
308  {
309  jack_error("sched_get_priority_max() failed.");
310  return false;
311  }
312 
313  *min_ptr = min;
314  *max_ptr = max;
315 
316  return true;
317 #else
318  return false;
319 #endif
320 }
321 
322 bool jack_tls_allocate_key(jack_tls_key *key_ptr)
323 {
324  int ret;
325 
326  ret = pthread_key_create(key_ptr, NULL);
327  if (ret != 0)
328  {
329  jack_error("pthread_key_create() failed with error %d", ret);
330  return false;
331  }
332 
333  return true;
334 }
335 
336 bool jack_tls_free_key(jack_tls_key key)
337 {
338  int ret;
339 
340  ret = pthread_key_delete(key);
341  if (ret != 0)
342  {
343  jack_error("pthread_key_delete() failed with error %d", ret);
344  return false;
345  }
346 
347  return true;
348 }
349 
350 bool jack_tls_set(jack_tls_key key, void *data_ptr)
351 {
352  int ret;
353 
354  ret = pthread_setspecific(key, (const void *)data_ptr);
355  if (ret != 0)
356  {
357  jack_error("pthread_setspecific() failed with error %d", ret);
358  return false;
359  }
360 
361  return true;
362 }
363 
364 void *jack_tls_get(jack_tls_key key)
365 {
366  return pthread_getspecific(key);
367 }
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107