/[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 1481 - (hide annotations) (download)
Wed Nov 14 23:42:15 2007 UTC (16 years, 5 months ago) by senoner
File size: 13043 byte(s)
* win32 port work in progress:
* - implemented win32 support in the following classes:
* Thread, Condition, Mutex, Path, LscpServer
* - lscp.y use DONTCARE instead of VOID
*  (a win32 symbol defined)
* - completed win32 editor plugin loader

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

  ViewVC Help
Powered by ViewVC