/[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 497 by persson, Sun Apr 10 11:55:44 2005 UTC revision 1424 by schoenebeck, Sun Oct 14 22:00:17 2007 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 - 2007 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    // 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    // Callback functions for the POSIX thread API
35    static void* __pthread_launcher(void* thread);
36    static void  __pthread_destructor(void* thread);
37    
38  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
39      this->bLockedMemory     = LockMemory;      this->bLockedMemory     = LockMemory;
40      this->isRealTime        = RealTime;      this->isRealTime        = RealTime;
     this->Running           = false;  
41      this->PriorityDelta     = PriorityDelta;      this->PriorityDelta     = PriorityDelta;
42      this->PriorityMax       = PriorityMax;      this->PriorityMax       = PriorityMax;
43      __thread_destructor_key = 0;      __thread_destructor_key = 0;
44      pthread_mutex_init(&__thread_state_mutex, NULL);      pthread_attr_init(&__thread_attr);
     pthread_cond_init(&__thread_start_condition, NULL);  
     pthread_cond_init(&__thread_exit_condition, NULL);  
45  }  }
46    
47  Thread::~Thread() {  Thread::~Thread() {
48      StopThread();      StopThread();
49      pthread_cond_destroy(&__thread_start_condition);      pthread_attr_destroy(&__thread_attr);
     pthread_cond_destroy(&__thread_exit_condition);  
     pthread_mutex_destroy(&__thread_state_mutex);  
50  }  }
51    
52  /**  /**
# Line 48  Thread::~Thread() { Line 56  Thread::~Thread() {
56   *  Main() method in your subclass.   *  Main() method in your subclass.
57   */   */
58  int Thread::StartThread() {  int Thread::StartThread() {
59      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
60      if (!Running) {      if (!RunningCondition.GetUnsafe()) {
61          SignalStartThread();          SignalStartThread();
62          pthread_cond_wait(&__thread_start_condition, &__thread_state_mutex);          // wait until thread started execution
63            RunningCondition.WaitIf(false);
64      }      }
65      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
66      return 0;      return 0;
67  }  }
68    
# Line 66  int Thread::StartThread() { Line 75  int Thread::StartThread() {
75   *  @see StartThread()   *  @see StartThread()
76   */   */
77  int Thread::SignalStartThread() {  int Thread::SignalStartThread() {
78        // prepare the thread properties
79        int res = pthread_attr_setinheritsched(&__thread_attr, PTHREAD_EXPLICIT_SCHED);
80        if (res) {
81            std::cerr << "Thread creation failed: Could not inherit thread properties."
82                      << std::endl << std::flush;
83            RunningCondition.Set(false);
84            return res;
85        }
86        res = pthread_attr_setdetachstate(&__thread_attr, PTHREAD_CREATE_JOINABLE);
87        if (res) {
88            std::cerr << "Thread creation failed: Could not request a joinable thread."
89                      << std::endl << std::flush;
90            RunningCondition.Set(false);
91            return res;
92        }
93        res = pthread_attr_setscope(&__thread_attr, PTHREAD_SCOPE_SYSTEM);
94        if (res) {
95            std::cerr << "Thread creation failed: Could not request system scope for thread scheduling."
96                      << std::endl << std::flush;
97            RunningCondition.Set(false);
98            return res;
99        }
100        res = pthread_attr_setstacksize(&__thread_attr, MIN_STACK_SIZE);
101        if (res) {
102            std::cerr << "Thread creation failed: Could not set minimum stack size."
103                      << std::endl << std::flush;
104            RunningCondition.Set(false);
105            return res;
106        }
107      // Create and run the thread      // Create and run the thread
108      int res = pthread_create(&this->__thread_id, NULL, __pthread_launcher, this);      res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
109      switch (res) {      switch (res) {
110          case 0: // Success          case 0: // Success
111              break;              break;
112          case EAGAIN:          case EAGAIN:
113              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."
114                        << std::endl << std::flush;                        << std::endl << std::flush;
115              this->Running = false;              RunningCondition.Set(false);
116              break;              break;
117          case EPERM:          case EPERM:
118              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."
119                        << std::endl << std::flush;                        << std::endl << std::flush;
120              this->Running = false;              RunningCondition.Set(false);
121              break;              break;
122          default:          default:
123              std::cerr << "Thread creation failed: Unknown cause."              std::cerr << "Thread creation failed: Unknown cause."
124                        << std::endl << std::flush;                        << std::endl << std::flush;
125              this->Running = false;              RunningCondition.Set(false);
126              break;              break;
127      }      }
128      return res;      return res;
# Line 95  int Thread::SignalStartThread() { Line 133  int Thread::SignalStartThread() {
133   *  it's execution before it will return.   *  it's execution before it will return.
134   */   */
135  int Thread::StopThread() {  int Thread::StopThread() {
136      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
137      if (Running) {      if (RunningCondition.GetUnsafe()) {
138          SignalStopThread();          SignalStopThread();
139          pthread_cond_wait(&__thread_exit_condition, &__thread_state_mutex);          // wait until thread stopped execution
140            RunningCondition.WaitIf(true);
141          pthread_detach(__thread_id);          pthread_detach(__thread_id);
142      }      }
143      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
144      return 0;      return 0;
145  }  }
146    
# Line 113  int Thread::StopThread() { Line 152  int Thread::StopThread() {
152   *  @see StopThread()   *  @see StopThread()
153   */   */
154  int Thread::SignalStopThread() {  int Thread::SignalStopThread() {
155        //FIXME: segfaults when thread is not yet running
156      pthread_cancel(__thread_id);      pthread_cancel(__thread_id);
157      return 0;      return 0;
158  }  }
159    
160  /**  /**
161     * Returns @c true in case the thread is currently running.
162     */
163    bool Thread::IsRunning() {
164        return RunningCondition.GetUnsafe();
165    }
166    
167    /**
168   *  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,
169   *  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
170   *  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 126  int Thread::SignalStopThread() { Line 173  int Thread::SignalStopThread() {
173   */   */
174  int Thread::SetSchedulingPriority() {  int Thread::SetSchedulingPriority() {
175  #if !defined(__APPLE__)  #if !defined(__APPLE__)
176        int policy;
177        const char* policyDescription = NULL;
178        if (isRealTime) { // becomes a RT thread
179            policy = SCHED_FIFO;
180            policyDescription = "realtime";
181        } else { // 'normal', non-RT thread
182            policy = SCHED_OTHER;
183            policyDescription = "normal (non-RT)";
184        }
185        // set selected scheduling policy and priority
186      struct sched_param schp;      struct sched_param schp;
   
     if (!isRealTime) return 0;  
   
     /*  
      * set the process to realtime privs  
      */  
187      memset(&schp, 0, sizeof(schp));      memset(&schp, 0, sizeof(schp));
188      if (this->PriorityMax == 1) {      if (isRealTime) { // it is not possible to change priority for the SCHED_OTHER policy
189          schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;          if (this->PriorityMax == 1) {
190                schp.sched_priority = sched_get_priority_max(policy) + this->PriorityDelta;
191            }
192            if (this->PriorityMax == -1) {
193                schp.sched_priority = sched_get_priority_min(policy) + this->PriorityDelta;
194            }
195      }      }
196      if (this->PriorityMax == -1) {      if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
197          schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;          std::cerr << "Thread: WARNING, can't assign "
198      }                    << policyDescription
199                      << " scheduling to thread!"
200      if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {                    << std::endl << std::flush;
         perror("Thread: WARNING, can't assign realtime scheduling to thread!");  
201          return -1;          return -1;
202      }      }
203  #endif  #endif
# Line 156  int Thread::LockMemory() { Line 211  int Thread::LockMemory() {
211  #if !defined(__APPLE__)  #if !defined(__APPLE__)
212      if (!bLockedMemory) return 0;      if (!bLockedMemory) return 0;
213      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
214          perror("Thread: WARNING, can't mlockall() memory!");          std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
215                      << std::flush;
216          return -1;          return -1;
217      }      }
218  #endif  #endif
# Line 170  int Thread::LockMemory() { Line 226  int Thread::LockMemory() {
226   *  CALL THIS METHOD YOURSELF!   *  CALL THIS METHOD YOURSELF!
227   */   */
228  void Thread::EnableDestructor() {  void Thread::EnableDestructor() {
229      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
230      pthread_key_create(&__thread_destructor_key, __pthread_destructor);      pthread_key_create(&__thread_destructor_key, __pthread_destructor);
231      pthread_setspecific(__thread_destructor_key, this);      pthread_setspecific(__thread_destructor_key, this);
232      Running = true;      RunningCondition.Set(true);
233      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
     pthread_cond_broadcast(&__thread_start_condition);  
234  }  }
235    
236  /**  /**
# Line 183  void Thread::EnableDestructor() { Line 238  void Thread::EnableDestructor() {
238   */   */
239  int Thread::Destructor() {  int Thread::Destructor() {
240      pthread_key_delete(__thread_destructor_key);      pthread_key_delete(__thread_destructor_key);
241      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Set(false);
     Running = false;  
     pthread_mutex_unlock(&__thread_state_mutex);  
     pthread_cond_broadcast(&__thread_exit_condition);  
242      return 0;      return 0;
243  }  }
244    
245  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
246  void* __pthread_launcher(void* thread) {  static void* __pthread_launcher(void* thread) {
247      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances
248      Thread* t;      Thread* t;
249      t = (Thread*) thread;      t = (Thread*) thread;
# Line 203  void* __pthread_launcher(void* thread) { Line 255  void* __pthread_launcher(void* thread) {
255  }  }
256    
257  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
258  void __pthread_destructor(void* thread) {  static void __pthread_destructor(void* thread) {
259      Thread* t;      Thread* t;
260      t = (Thread*) thread;      t = (Thread*) thread;
261      t->Destructor();      t->Destructor();
262  }  }
263    
264    } // namespace LinuxSampler

Legend:
Removed from v.497  
changed lines
  Added in v.1424

  ViewVC Help
Powered by ViewVC