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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1481 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2007 Christian Schoenebeck *
7 * *
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 // 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 namespace LinuxSampler {
33
34 #if defined(WIN32)
35 // Callback functions for the WIN32 thread API
36 DWORD WINAPI __win32thread_launcher(LPVOID lpParameter);
37 #else
38 // Callback functions for the POSIX thread API
39 static void* __pthread_launcher(void* thread);
40 static void __pthread_destructor(void* thread);
41 #endif
42
43 Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
44 this->bLockedMemory = LockMemory;
45 this->isRealTime = RealTime;
46 this->PriorityDelta = PriorityDelta;
47 this->PriorityMax = PriorityMax;
48 #if defined(WIN32)
49 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
50 win32isRunning = false;
51 #endif
52 #else
53 __thread_destructor_key = 0;
54 pthread_attr_init(&__thread_attr);
55 #endif
56 }
57
58 Thread::~Thread() {
59 StopThread();
60 #if defined(WIN32)
61 #else
62 pthread_attr_destroy(&__thread_attr);
63 #endif
64 }
65
66 /**
67 * 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 */
72 int Thread::StartThread() {
73 #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 RunningCondition.Lock();
85 if (!RunningCondition.GetUnsafe()) {
86 SignalStartThread();
87 // wait until thread started execution
88 RunningCondition.WaitIf(false);
89 }
90 RunningCondition.Unlock();
91 return 0;
92 #endif
93 }
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 #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 // 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 // Create and run the thread
154 res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
155 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 RunningCondition.Set(false);
162 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 RunningCondition.Set(false);
167 break;
168 default:
169 std::cerr << "Thread creation failed: Unknown cause."
170 << std::endl << std::flush;
171 RunningCondition.Set(false);
172 break;
173 }
174 return res;
175 #endif
176 }
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 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
184 SignalStopThread();
185 win32isRunning = false;
186 return 0;
187 #endif
188 RunningCondition.Lock();
189 if (RunningCondition.GetUnsafe()) {
190 SignalStopThread();
191 // wait until thread stopped execution
192 RunningCondition.WaitIf(true);
193 #if defined(WIN32)
194 #else
195 pthread_detach(__thread_id);
196 #endif
197 }
198 RunningCondition.Unlock();
199 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 *
207 * @see StopThread()
208 */
209 int Thread::SignalStopThread() {
210 //FIXME: segfaults when thread is not yet running
211 #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 pthread_cancel(__thread_id);
223 #endif
224 return 0;
225 }
226
227 /**
228 * Returns @c true in case the thread is currently running.
229 */
230 bool Thread::IsRunning() {
231 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
232 return win32isRunning;
233 #else
234 return RunningCondition.GetUnsafe();
235 #endif
236 }
237
238 /**
239 * 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 #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 #if !defined(__APPLE__)
281 int policy;
282 const char* policyDescription = NULL;
283 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 struct sched_param schp;
292 memset(&schp, 0, sizeof(schp));
293 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 }
301 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 return -1;
307 }
308 #endif
309 return 0;
310 #endif
311 }
312
313 /**
314 * Locks the memory so it will not be swapped out by the operating system.
315 */
316 int Thread::LockMemory() {
317 #if defined(WIN32)
318 return 0;
319 #else
320 #if !defined(__APPLE__)
321 if (!bLockedMemory) return 0;
322 if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
323 std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
324 << std::flush;
325 return -1;
326 }
327 #endif
328 return 0;
329 #endif
330 }
331
332 /**
333 * 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 #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
340 win32isRunning = true;
341 return;
342 #endif
343 RunningCondition.Lock();
344 #if defined(WIN32)
345 #else
346 pthread_key_create(&__thread_destructor_key, __pthread_destructor);
347 pthread_setspecific(__thread_destructor_key, this);
348 #endif
349 RunningCondition.Set(true);
350 RunningCondition.Unlock();
351 }
352
353 /**
354 * Will be called by the kernel when the thread stops it's execution.
355 */
356 int Thread::Destructor() {
357 #if defined(WIN32)
358 #else
359 pthread_key_delete(__thread_destructor_key);
360 RunningCondition.Set(false);
361 #endif
362 return 0;
363 }
364
365 #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 /// Callback function for the POSIX thread API
377 static void* __pthread_launcher(void* thread) {
378 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
379 Thread* t;
380 t = (Thread*) thread;
381 t->SetSchedulingPriority();
382 t->LockMemory();
383 t->EnableDestructor();
384 t->Main();
385 return NULL;
386 }
387 #endif
388
389 #if defined(WIN32)
390 #else
391 /// Callback function for the POSIX thread API
392 static void __pthread_destructor(void* thread) {
393 Thread* t;
394 t = (Thread*) thread;
395 t->Destructor();
396 }
397 #endif
398
399 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC