/[svn]/linuxsampler/trunk/src/common/Thread.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/common/Thread.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2185 - (hide annotations) (download)
Sun Jun 19 09:09:38 2011 UTC (13 years ago) by persson
File size: 13223 byte(s)
* fixed compilation with gcc 4.6.1
* another "make dist" fix, for LV2 plugin
* made --enable-pthread-testcancel default on Mac OS X
* Mac OS X: fixed hanging threads

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 persson 2185 * Copyright (C) 2005 - 2011 Christian Schoenebeck *
7 schoenebeck 53 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "Thread.h"
25    
26 persson 2185 #if HAVE_CONFIG_H
27     # include <config.h>
28     #endif
29    
30 schoenebeck 1221 // this is the minimum stack size a thread will be spawned with
31     // if this value is too small, the OS will allocate memory on demand and
32     // thus might lead to dropouts in realtime threads
33     // TODO: should be up for testing to get a reasonable good value
34     #define MIN_STACK_SIZE 524288
35    
36 schoenebeck 1212 namespace LinuxSampler {
37    
38 senoner 1481 #if defined(WIN32)
39     // Callback functions for the WIN32 thread API
40     DWORD WINAPI __win32thread_launcher(LPVOID lpParameter);
41     #else
42 schoenebeck 1424 // Callback functions for the POSIX thread API
43     static void* __pthread_launcher(void* thread);
44     static void __pthread_destructor(void* thread);
45 senoner 1481 #endif
46 schoenebeck 1424
47 schoenebeck 392 Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
48     this->bLockedMemory = LockMemory;
49 schoenebeck 53 this->isRealTime = RealTime;
50     this->PriorityDelta = PriorityDelta;
51     this->PriorityMax = PriorityMax;
52 senoner 1481 #if defined(WIN32)
53     #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
54     win32isRunning = false;
55     #endif
56     #else
57 schoenebeck 53 __thread_destructor_key = 0;
58 schoenebeck 1221 pthread_attr_init(&__thread_attr);
59 senoner 1481 #endif
60 schoenebeck 53 }
61    
62     Thread::~Thread() {
63 schoenebeck 57 StopThread();
64 senoner 1481 #if defined(WIN32)
65     #else
66 schoenebeck 1221 pthread_attr_destroy(&__thread_attr);
67 senoner 1481 #endif
68 schoenebeck 53 }
69    
70     /**
71 schoenebeck 57 * Starts the thread. This method will wait until the thread actually
72     * started it's execution before it will return. The abstract method
73     * Main() is the entry point for the new thread. You have to implement the
74     * Main() method in your subclass.
75 schoenebeck 53 */
76     int Thread::StartThread() {
77 senoner 1481 #if defined (WIN32_SIGNALSTARTTHREAD_WORKAROUND)
78     // poll the win32isRunning variable and sleep 1msec inbetween
79     if(!win32isRunning) {
80     SignalStartThread();
81     while(1) {
82     Sleep(1);
83     if(win32isRunning) break;
84     }
85     }
86     return 0;
87     #else
88 schoenebeck 1221 RunningCondition.Lock();
89     if (!RunningCondition.GetUnsafe()) {
90 schoenebeck 57 SignalStartThread();
91 schoenebeck 1221 // wait until thread started execution
92     RunningCondition.WaitIf(false);
93 schoenebeck 57 }
94 schoenebeck 1221 RunningCondition.Unlock();
95 schoenebeck 57 return 0;
96 senoner 1481 #endif
97 schoenebeck 57 }
98    
99     /**
100     * Starts the thread. This method will signal to start the thread and
101     * return immediately. Note that the thread might not yet run when this
102     * method returns! The abstract method Main() is the entry point for the
103     * new thread. You have to implement the Main() method in your subclass.
104     *
105     * @see StartThread()
106     */
107     int Thread::SignalStartThread() {
108 senoner 1481 #if defined(WIN32)
109     LPVOID lpParameter;
110     hThread = CreateThread(
111     NULL, // no security attributes
112     MIN_STACK_SIZE,
113     __win32thread_launcher,
114     this,
115     0,
116     &lpThreadId);
117     if(hThread == NULL) {
118     std::cerr << "Thread creation failed: Error" << GetLastError() << std::endl << std::flush;
119     #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
120     win32isRunning = false;
121     #else
122     RunningCondition.Set(false);
123     #endif
124     return -1;
125     }
126     return 0;
127     #else
128 schoenebeck 1221 // prepare the thread properties
129     int res = pthread_attr_setinheritsched(&__thread_attr, PTHREAD_EXPLICIT_SCHED);
130     if (res) {
131     std::cerr << "Thread creation failed: Could not inherit thread properties."
132     << std::endl << std::flush;
133     RunningCondition.Set(false);
134     return res;
135     }
136     res = pthread_attr_setdetachstate(&__thread_attr, PTHREAD_CREATE_JOINABLE);
137     if (res) {
138     std::cerr << "Thread creation failed: Could not request a joinable thread."
139     << std::endl << std::flush;
140     RunningCondition.Set(false);
141     return res;
142     }
143     res = pthread_attr_setscope(&__thread_attr, PTHREAD_SCOPE_SYSTEM);
144     if (res) {
145     std::cerr << "Thread creation failed: Could not request system scope for thread scheduling."
146     << std::endl << std::flush;
147     RunningCondition.Set(false);
148     return res;
149     }
150     res = pthread_attr_setstacksize(&__thread_attr, MIN_STACK_SIZE);
151     if (res) {
152     std::cerr << "Thread creation failed: Could not set minimum stack size."
153     << std::endl << std::flush;
154     RunningCondition.Set(false);
155     return res;
156     }
157 nagata 1649
158 schoenebeck 53 // Create and run the thread
159 schoenebeck 1221 res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
160 schoenebeck 53 switch (res) {
161     case 0: // Success
162     break;
163     case EAGAIN:
164     std::cerr << "Thread creation failed: System doesn't allow to create another thread."
165     << std::endl << std::flush;
166 schoenebeck 1221 RunningCondition.Set(false);
167 schoenebeck 53 break;
168     case EPERM:
169     std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."
170     << std::endl << std::flush;
171 schoenebeck 1221 RunningCondition.Set(false);
172 schoenebeck 53 break;
173     default:
174     std::cerr << "Thread creation failed: Unknown cause."
175     << std::endl << std::flush;
176 schoenebeck 1221 RunningCondition.Set(false);
177 schoenebeck 53 break;
178     }
179     return res;
180 senoner 1481 #endif
181 schoenebeck 53 }
182    
183     /**
184     * Stops the thread. This method will wait until the thread actually stopped
185     * it's execution before it will return.
186     */
187     int Thread::StopThread() {
188 senoner 1481 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
189     SignalStopThread();
190     win32isRunning = false;
191     return 0;
192     #endif
193 schoenebeck 1221 RunningCondition.Lock();
194     if (RunningCondition.GetUnsafe()) {
195 schoenebeck 53 SignalStopThread();
196 schoenebeck 1221 // wait until thread stopped execution
197     RunningCondition.WaitIf(true);
198 senoner 1481 #if defined(WIN32)
199     #else
200 schoenebeck 351 pthread_detach(__thread_id);
201 senoner 1481 #endif
202 schoenebeck 53 }
203 schoenebeck 1221 RunningCondition.Unlock();
204 schoenebeck 53 return 0;
205     }
206    
207     /**
208     * Stops the thread. This method will signal to stop the thread and return
209     * immediately. Note that the thread might still run when this method
210     * returns!
211 schoenebeck 57 *
212     * @see StopThread()
213 schoenebeck 53 */
214     int Thread::SignalStopThread() {
215 schoenebeck 1221 //FIXME: segfaults when thread is not yet running
216 senoner 1481 #if defined(WIN32)
217     BOOL res;
218     res = TerminateThread(hThread, 0); // we set ExitCode to 0
219     //res = WaitForSingleObject( hThread, INFINITE);
220     //myprint(("Thread::SignalStopThread: WaitForSingleObject( hThread, INFINITE) res=%d\n",res));
221     #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
222     win32isRunning = false;
223     #else
224     RunningCondition.Set(false);
225     #endif
226 nagata 1649 #else
227 schoenebeck 53 pthread_cancel(__thread_id);
228 senoner 1481 #endif
229 schoenebeck 53 return 0;
230     }
231    
232     /**
233 schoenebeck 1212 * Returns @c true in case the thread is currently running.
234     */
235     bool Thread::IsRunning() {
236 senoner 1481 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
237     return win32isRunning;
238     #else
239 schoenebeck 1221 return RunningCondition.GetUnsafe();
240 senoner 1481 #endif
241 schoenebeck 1212 }
242    
243     /**
244 schoenebeck 53 * Sets the process SCHED_FIFO policy, if max=1 then set at max priority,
245     * else use min priority. delta is added to the priority so that we can
246     * for example set 3 SCHED_FIFO tasks to different priorities by specifying
247     * delta 0 , -1 , -2 ( 0 = highest priority because -1 is subtracted to the
248     * current priority).
249     */
250     int Thread::SetSchedulingPriority() {
251 senoner 1481 #if defined(WIN32)
252     DWORD dwPriorityClass;
253     int nPriority;
254    
255     if(isRealTime) {
256     dwPriorityClass = REALTIME_PRIORITY_CLASS;
257     if (this->PriorityMax == 1) {
258     if(this->PriorityDelta == 0) nPriority = THREAD_PRIORITY_TIME_CRITICAL;
259     else nPriority = 7 + this->PriorityDelta;
260     }
261     else nPriority = THREAD_PRIORITY_NORMAL + this->PriorityDelta;
262     }
263     else {
264     dwPriorityClass = NORMAL_PRIORITY_CLASS;
265     nPriority = THREAD_PRIORITY_NORMAL + this->PriorityDelta;
266     }
267    
268     BOOL res;
269     // FIXME: priority class (realtime) does not work yet, gives error. check why.
270     #if 0
271     res = SetPriorityClass( hThread, dwPriorityClass );
272     if(res == false) {
273     std::cerr << "Thread: WARNING, setPriorityClass " << dwPriorityClass << "failed. Error " << GetLastError() << "\n";
274     return -1;
275     }
276    
277     res = SetThreadPriority( hThread, nPriority );
278     if(res == false) {
279     std::cerr << "Thread: WARNING, setThreadPriority " << nPriority << "failed. Error " << GetLastError() << "\n";
280     return -1;
281     }
282     #endif
283     return 0;
284     #else
285 schoenebeck 361 #if !defined(__APPLE__)
286 schoenebeck 1221 int policy;
287 persson 1222 const char* policyDescription = NULL;
288 schoenebeck 1221 if (isRealTime) { // becomes a RT thread
289     policy = SCHED_FIFO;
290     policyDescription = "realtime";
291     } else { // 'normal', non-RT thread
292     policy = SCHED_OTHER;
293     policyDescription = "normal (non-RT)";
294     }
295     // set selected scheduling policy and priority
296 schoenebeck 53 struct sched_param schp;
297     memset(&schp, 0, sizeof(schp));
298 persson 1222 if (isRealTime) { // it is not possible to change priority for the SCHED_OTHER policy
299     if (this->PriorityMax == 1) {
300     schp.sched_priority = sched_get_priority_max(policy) + this->PriorityDelta;
301     }
302     if (this->PriorityMax == -1) {
303     schp.sched_priority = sched_get_priority_min(policy) + this->PriorityDelta;
304     }
305 schoenebeck 53 }
306 schoenebeck 1221 if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
307     std::cerr << "Thread: WARNING, can't assign "
308     << policyDescription
309     << " scheduling to thread!"
310     << std::endl << std::flush;
311 schoenebeck 53 return -1;
312     }
313 schoenebeck 361 #endif
314 schoenebeck 53 return 0;
315 senoner 1481 #endif
316 schoenebeck 53 }
317    
318     /**
319 schoenebeck 392 * Locks the memory so it will not be swapped out by the operating system.
320     */
321     int Thread::LockMemory() {
322 senoner 1481 #if defined(WIN32)
323     return 0;
324     #else
325 letz 399 #if !defined(__APPLE__)
326 schoenebeck 392 if (!bLockedMemory) return 0;
327     if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
328 schoenebeck 1221 std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
329     << std::flush;
330 schoenebeck 392 return -1;
331     }
332 letz 399 #endif
333 schoenebeck 392 return 0;
334 senoner 1481 #endif
335 schoenebeck 392 }
336    
337     /**
338 schoenebeck 53 * Registers thread destructor callback function which will be executed when
339     * the thread stops it's execution and sets the 'Running' flag to true. This
340     * method will be called by the __pthread_launcher callback function, DO NOT
341     * CALL THIS METHOD YOURSELF!
342     */
343     void Thread::EnableDestructor() {
344 senoner 1481 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
345     win32isRunning = true;
346     return;
347     #endif
348 schoenebeck 1221 RunningCondition.Lock();
349 senoner 1481 #if defined(WIN32)
350     #else
351 schoenebeck 53 pthread_key_create(&__thread_destructor_key, __pthread_destructor);
352     pthread_setspecific(__thread_destructor_key, this);
353 senoner 1481 #endif
354 schoenebeck 1221 RunningCondition.Set(true);
355     RunningCondition.Unlock();
356 schoenebeck 53 }
357    
358     /**
359     * Will be called by the kernel when the thread stops it's execution.
360     */
361     int Thread::Destructor() {
362 senoner 1481 #if defined(WIN32)
363     #else
364 schoenebeck 53 pthread_key_delete(__thread_destructor_key);
365 schoenebeck 1221 RunningCondition.Set(false);
366 senoner 1481 #endif
367 persson 497 return 0;
368 schoenebeck 53 }
369    
370 persson 2185 void Thread::TestCancel() {
371     #if CONFIG_PTHREAD_TESTCANCEL
372     pthread_testcancel();
373     #endif
374     }
375    
376 senoner 1481 #if defined(WIN32)
377     DWORD WINAPI __win32thread_launcher(LPVOID lpParameter) {
378     Thread* t;
379     t = (Thread*) lpParameter;
380     t->SetSchedulingPriority();
381     t->LockMemory();
382     t->EnableDestructor();
383     t->Main();
384     return 0;
385     }
386     #else
387 schoenebeck 53 /// Callback function for the POSIX thread API
388 schoenebeck 1424 static void* __pthread_launcher(void* thread) {
389 nagata 1649 #if !CONFIG_PTHREAD_TESTCANCEL
390 schoenebeck 63 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
391 nagata 1649 #endif
392    
393 schoenebeck 53 Thread* t;
394     t = (Thread*) thread;
395 schoenebeck 57 t->SetSchedulingPriority();
396 schoenebeck 392 t->LockMemory();
397 schoenebeck 53 t->EnableDestructor();
398     t->Main();
399 persson 497 return NULL;
400 schoenebeck 53 }
401 senoner 1481 #endif
402 schoenebeck 53
403 senoner 1481 #if defined(WIN32)
404     #else
405 schoenebeck 53 /// Callback function for the POSIX thread API
406 schoenebeck 1424 static void __pthread_destructor(void* thread) {
407 schoenebeck 53 Thread* t;
408     t = (Thread*) thread;
409     t->Destructor();
410     }
411 senoner 1481 #endif
412 schoenebeck 1212
413     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC