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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 57 by schoenebeck, Sun May 2 17:45:43 2004 UTC revision 2185 by persson, Sun Jun 19 09:09:38 2011 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2011 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 22  Line 23 
23    
24  #include "Thread.h"  #include "Thread.h"
25    
26  Thread::Thread(bool RealTime, int PriorityMax, int PriorityDelta) {  #if HAVE_CONFIG_H
27    # include <config.h>
28    #endif
29    
30    // 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    namespace LinuxSampler {
37    
38    #if defined(WIN32)
39    // Callback functions for the WIN32 thread API
40    DWORD WINAPI __win32thread_launcher(LPVOID lpParameter);
41    #else
42    // Callback functions for the POSIX thread API
43    static void* __pthread_launcher(void* thread);
44    static void  __pthread_destructor(void* thread);
45    #endif
46    
47    Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
48        this->bLockedMemory     = LockMemory;
49      this->isRealTime        = RealTime;      this->isRealTime        = RealTime;
     this->Running           = false;  
50      this->PriorityDelta     = PriorityDelta;      this->PriorityDelta     = PriorityDelta;
51      this->PriorityMax       = PriorityMax;      this->PriorityMax       = PriorityMax;
52    #if defined(WIN32)
53    #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
54        win32isRunning = false;
55    #endif
56    #else
57      __thread_destructor_key = 0;      __thread_destructor_key = 0;
58      pthread_mutex_init(&__thread_state_mutex, NULL);      pthread_attr_init(&__thread_attr);
59      pthread_cond_init(&__thread_start_condition, NULL);  #endif
     pthread_cond_init(&__thread_exit_condition, NULL);  
60  }  }
61    
62  Thread::~Thread() {  Thread::~Thread() {
63      StopThread();      StopThread();
64      pthread_cond_destroy(&__thread_start_condition);  #if defined(WIN32)
65      pthread_cond_destroy(&__thread_exit_condition);  #else
66      pthread_mutex_destroy(&__thread_state_mutex);      pthread_attr_destroy(&__thread_attr);
67    #endif
68  }  }
69    
70  /**  /**
# Line 47  Thread::~Thread() { Line 74  Thread::~Thread() {
74   *  Main() method in your subclass.   *  Main() method in your subclass.
75   */   */
76  int Thread::StartThread() {  int Thread::StartThread() {
77      pthread_mutex_lock(&__thread_state_mutex);  #if defined (WIN32_SIGNALSTARTTHREAD_WORKAROUND)
78      if (!Running) {      // 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        RunningCondition.Lock();
89        if (!RunningCondition.GetUnsafe()) {
90          SignalStartThread();          SignalStartThread();
91          pthread_cond_wait(&__thread_start_condition, &__thread_state_mutex);          // wait until thread started execution
92            RunningCondition.WaitIf(false);
93      }      }
94      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
95      return 0;      return 0;
96    #endif
97  }  }
98    
99  /**  /**
# Line 65  int Thread::StartThread() { Line 105  int Thread::StartThread() {
105   *  @see StartThread()   *  @see StartThread()
106   */   */
107  int Thread::SignalStartThread() {  int Thread::SignalStartThread() {
108    #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        // 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    
158      // Create and run the thread      // Create and run the thread
159      int res = pthread_create(&this->__thread_id, NULL, __pthread_launcher, this);      res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
160      switch (res) {      switch (res) {
161          case 0: // Success          case 0: // Success
162              break;              break;
163          case EAGAIN:          case EAGAIN:
164              std::cerr << "Thread creation failed: System doesn't allow to create another thread."              std::cerr << "Thread creation failed: System doesn't allow to create another thread."
165                        << std::endl << std::flush;                        << std::endl << std::flush;
166              this->Running = false;              RunningCondition.Set(false);
167              break;              break;
168          case EPERM:          case EPERM:
169              std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."              std::cerr << "Thread creation failed: You're lacking permisssions to set required scheduling policy and parameters."
170                        << std::endl << std::flush;                        << std::endl << std::flush;
171              this->Running = false;              RunningCondition.Set(false);
172              break;              break;
173          default:          default:
174              std::cerr << "Thread creation failed: Unknown cause."              std::cerr << "Thread creation failed: Unknown cause."
175                        << std::endl << std::flush;                        << std::endl << std::flush;
176              this->Running = false;              RunningCondition.Set(false);
177              break;              break;
178      }      }
179      return res;      return res;
180    #endif
181  }  }
182    
183  /**  /**
# Line 94  int Thread::SignalStartThread() { Line 185  int Thread::SignalStartThread() {
185   *  it's execution before it will return.   *  it's execution before it will return.
186   */   */
187  int Thread::StopThread() {  int Thread::StopThread() {
188      pthread_mutex_lock(&__thread_state_mutex);  #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
189      if (Running) {      SignalStopThread();
190        win32isRunning = false;
191        return 0;
192    #endif
193        RunningCondition.Lock();
194        if (RunningCondition.GetUnsafe()) {
195          SignalStopThread();          SignalStopThread();
196          pthread_cond_wait(&__thread_exit_condition, &__thread_state_mutex);          // wait until thread stopped execution
197            RunningCondition.WaitIf(true);
198            #if defined(WIN32)
199            #else          
200            pthread_detach(__thread_id);
201            #endif          
202      }      }
203      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
204      return 0;      return 0;
205  }  }
206    
# Line 111  int Thread::StopThread() { Line 212  int Thread::StopThread() {
212   *  @see StopThread()   *  @see StopThread()
213   */   */
214  int Thread::SignalStopThread() {  int Thread::SignalStopThread() {
215        //FIXME: segfaults when thread is not yet running
216    #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    #else
227      pthread_cancel(__thread_id);      pthread_cancel(__thread_id);
228    #endif  
229      return 0;      return 0;
230  }  }
231    
232  /**  /**
233     * Returns @c true in case the thread is currently running.
234     */
235    bool Thread::IsRunning() {
236        #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
237        return win32isRunning;
238        #else
239        return RunningCondition.GetUnsafe();
240        #endif
241    }
242    
243    /**
244   *  Sets the process SCHED_FIFO policy,  if max=1 then set at max priority,   *  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   *  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   *  for example set 3 SCHED_FIFO tasks to different priorities by specifying
# Line 123  int Thread::SignalStopThread() { Line 248  int Thread::SignalStopThread() {
248   *  current priority).   *  current priority).
249   */   */
250  int Thread::SetSchedulingPriority() {  int Thread::SetSchedulingPriority() {
251      struct sched_param schp;  #if defined(WIN32)
252        DWORD dwPriorityClass;
253      if (!isRealTime) return 0;      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      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {      BOOL res;
269          perror("WARNING, can't mlockall() memory!");      // 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       * set the process to realtime privs      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    #if !defined(__APPLE__)
286        int policy;
287        const char* policyDescription = NULL;
288        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        struct sched_param schp;
297      memset(&schp, 0, sizeof(schp));      memset(&schp, 0, sizeof(schp));
298      if (this->PriorityMax == 1) {      if (isRealTime) { // it is not possible to change priority for the SCHED_OTHER policy
299          schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;          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      }      }
306      if (this->PriorityMax == -1) {      if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
307          schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;          std::cerr << "Thread: WARNING, can't assign "
308                      << policyDescription
309                      << " scheduling to thread!"
310                      << std::endl << std::flush;
311            return -1;
312      }      }
313    #endif
314        return 0;
315    #endif  
316    }
317    
318      if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {  /**
319          perror("sched_setscheduler");   * Locks the memory so it will not be swapped out by the operating system.
320     */
321    int Thread::LockMemory() {
322    #if defined(WIN32)
323        return 0;
324    #else
325    #if !defined(__APPLE__)
326        if (!bLockedMemory) return 0;
327        if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
328            std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
329                      << std::flush;
330          return -1;          return -1;
331      }      }
332    #endif
333      return 0;      return 0;
334    #endif  
335  }  }
336    
337  /**  /**
# Line 157  int Thread::SetSchedulingPriority() { Line 341  int Thread::SetSchedulingPriority() {
341   *  CALL THIS METHOD YOURSELF!   *  CALL THIS METHOD YOURSELF!
342   */   */
343  void Thread::EnableDestructor() {  void Thread::EnableDestructor() {
344      pthread_mutex_lock(&__thread_state_mutex);  #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
345        win32isRunning = true;
346        return;    
347    #endif
348        RunningCondition.Lock();
349    #if defined(WIN32)
350    #else  
351      pthread_key_create(&__thread_destructor_key, __pthread_destructor);      pthread_key_create(&__thread_destructor_key, __pthread_destructor);
352      pthread_setspecific(__thread_destructor_key, this);      pthread_setspecific(__thread_destructor_key, this);
353      Running = true;  #endif  
354      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Set(true);
355      pthread_cond_broadcast(&__thread_start_condition);      RunningCondition.Unlock();
356  }  }
357    
358  /**  /**
359   *  Will be called by the kernel when the thread stops it's execution.   *  Will be called by the kernel when the thread stops it's execution.
360   */   */
361  int Thread::Destructor() {  int Thread::Destructor() {
362    #if defined(WIN32)
363    #else
364      pthread_key_delete(__thread_destructor_key);      pthread_key_delete(__thread_destructor_key);
365      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Set(false);
366      Running = false;  #endif  
367      pthread_mutex_unlock(&__thread_state_mutex);      return 0;
368      pthread_cond_broadcast(&__thread_exit_condition);  }
369    
370    void Thread::TestCancel() {
371    #if CONFIG_PTHREAD_TESTCANCEL
372        pthread_testcancel();
373    #endif
374  }  }
375    
376    #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  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
388  void* __pthread_launcher(void* thread) {  static void* __pthread_launcher(void* thread) {
389    #if !CONFIG_PTHREAD_TESTCANCEL
390        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
391    #endif
392    
393      Thread* t;      Thread* t;
394      t = (Thread*) thread;      t = (Thread*) thread;
395      t->SetSchedulingPriority();      t->SetSchedulingPriority();
396        t->LockMemory();
397      t->EnableDestructor();      t->EnableDestructor();
398      t->Main();      t->Main();
399        return NULL;
400  }  }
401    #endif
402    
403    #if defined(WIN32)
404    #else
405  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
406  void __pthread_destructor(void* thread) {  static void __pthread_destructor(void* thread) {
407      Thread* t;      Thread* t;
408      t = (Thread*) thread;      t = (Thread*) thread;
409      t->Destructor();      t->Destructor();
410  }  }
411    #endif
412    
413    } // namespace LinuxSampler

Legend:
Removed from v.57  
changed lines
  Added in v.2185

  ViewVC Help
Powered by ViewVC