/[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 1220 by schoenebeck, Tue May 29 23:59:36 2007 UTC revision 1221 by schoenebeck, Wed Jun 6 18:50:03 2007 UTC
# Line 23  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 {  namespace LinuxSampler {
33    
34  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
35      this->bLockedMemory     = LockMemory;      this->bLockedMemory     = LockMemory;
36      this->isRealTime        = RealTime;      this->isRealTime        = RealTime;
     this->Running           = false;  
37      this->PriorityDelta     = PriorityDelta;      this->PriorityDelta     = PriorityDelta;
38      this->PriorityMax       = PriorityMax;      this->PriorityMax       = PriorityMax;
39      __thread_destructor_key = 0;      __thread_destructor_key = 0;
40      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);  
41  }  }
42    
43  Thread::~Thread() {  Thread::~Thread() {
44      StopThread();      StopThread();
45      pthread_cond_destroy(&__thread_start_condition);      pthread_attr_destroy(&__thread_attr);
     pthread_cond_destroy(&__thread_exit_condition);  
     pthread_mutex_destroy(&__thread_state_mutex);  
46  }  }
47    
48  /**  /**
# Line 51  Thread::~Thread() { Line 52  Thread::~Thread() {
52   *  Main() method in your subclass.   *  Main() method in your subclass.
53   */   */
54  int Thread::StartThread() {  int Thread::StartThread() {
55      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
56      if (!Running) {      if (!RunningCondition.GetUnsafe()) {
57          SignalStartThread();          SignalStartThread();
58          pthread_cond_wait(&__thread_start_condition, &__thread_state_mutex);          // wait until thread started execution
59            RunningCondition.WaitIf(false);
60      }      }
61      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
62      return 0;      return 0;
63  }  }
64    
# Line 69  int Thread::StartThread() { Line 71  int Thread::StartThread() {
71   *  @see StartThread()   *  @see StartThread()
72   */   */
73  int Thread::SignalStartThread() {  int Thread::SignalStartThread() {
74        // prepare the thread properties
75        int res = pthread_attr_setinheritsched(&__thread_attr, PTHREAD_EXPLICIT_SCHED);
76        if (res) {
77            std::cerr << "Thread creation failed: Could not inherit thread properties."
78                      << std::endl << std::flush;
79            RunningCondition.Set(false);
80            return res;
81        }
82        res = pthread_attr_setdetachstate(&__thread_attr, PTHREAD_CREATE_JOINABLE);
83        if (res) {
84            std::cerr << "Thread creation failed: Could not request a joinable thread."
85                      << std::endl << std::flush;
86            RunningCondition.Set(false);
87            return res;
88        }
89        res = pthread_attr_setscope(&__thread_attr, PTHREAD_SCOPE_SYSTEM);
90        if (res) {
91            std::cerr << "Thread creation failed: Could not request system scope for thread scheduling."
92                      << std::endl << std::flush;
93            RunningCondition.Set(false);
94            return res;
95        }
96        res = pthread_attr_setstacksize(&__thread_attr, MIN_STACK_SIZE);
97        if (res) {
98            std::cerr << "Thread creation failed: Could not set minimum stack size."
99                      << std::endl << std::flush;
100            RunningCondition.Set(false);
101            return res;
102        }
103      // Create and run the thread      // Create and run the thread
104      int res = pthread_create(&this->__thread_id, NULL, __pthread_launcher, this);      res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);
105      switch (res) {      switch (res) {
106          case 0: // Success          case 0: // Success
107              break;              break;
108          case EAGAIN:          case EAGAIN:
109              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."
110                        << std::endl << std::flush;                        << std::endl << std::flush;
111              this->Running = false;              RunningCondition.Set(false);
112              break;              break;
113          case EPERM:          case EPERM:
114              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."
115                        << std::endl << std::flush;                        << std::endl << std::flush;
116              this->Running = false;              RunningCondition.Set(false);
117              break;              break;
118          default:          default:
119              std::cerr << "Thread creation failed: Unknown cause."              std::cerr << "Thread creation failed: Unknown cause."
120                        << std::endl << std::flush;                        << std::endl << std::flush;
121              this->Running = false;              RunningCondition.Set(false);
122              break;              break;
123      }      }
124      return res;      return res;
# Line 98  int Thread::SignalStartThread() { Line 129  int Thread::SignalStartThread() {
129   *  it's execution before it will return.   *  it's execution before it will return.
130   */   */
131  int Thread::StopThread() {  int Thread::StopThread() {
132      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
133      if (Running) {      if (RunningCondition.GetUnsafe()) {
134          SignalStopThread();          SignalStopThread();
135          pthread_cond_wait(&__thread_exit_condition, &__thread_state_mutex);          // wait until thread stopped execution
136            RunningCondition.WaitIf(true);
137          pthread_detach(__thread_id);          pthread_detach(__thread_id);
138      }      }
139      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
140      return 0;      return 0;
141  }  }
142    
# Line 116  int Thread::StopThread() { Line 148  int Thread::StopThread() {
148   *  @see StopThread()   *  @see StopThread()
149   */   */
150  int Thread::SignalStopThread() {  int Thread::SignalStopThread() {
151        //FIXME: segfaults when thread is not yet running
152      pthread_cancel(__thread_id);      pthread_cancel(__thread_id);
153      return 0;      return 0;
154  }  }
# Line 124  int Thread::SignalStopThread() { Line 157  int Thread::SignalStopThread() {
157   * Returns @c true in case the thread is currently running.   * Returns @c true in case the thread is currently running.
158   */   */
159  bool Thread::IsRunning() {  bool Thread::IsRunning() {
160      return Running;      return RunningCondition.GetUnsafe();
161  }  }
162    
163  /**  /**
# Line 136  bool Thread::IsRunning() { Line 169  bool Thread::IsRunning() {
169   */   */
170  int Thread::SetSchedulingPriority() {  int Thread::SetSchedulingPriority() {
171  #if !defined(__APPLE__)  #if !defined(__APPLE__)
172        int policy;
173        char* policyDescription = NULL;
174        if (isRealTime) { // becomes a RT thread
175            policy = SCHED_FIFO;
176            policyDescription = "realtime";
177        } else { // 'normal', non-RT thread
178            policy = SCHED_OTHER;
179            policyDescription = "normal (non-RT)";
180        }
181        // set selected scheduling policy and priority
182      struct sched_param schp;      struct sched_param schp;
   
     if (!isRealTime) return 0;  
   
     /*  
      * set the process to realtime privs  
      */  
183      memset(&schp, 0, sizeof(schp));      memset(&schp, 0, sizeof(schp));
184      if (this->PriorityMax == 1) {      if (this->PriorityMax == 1) {
185          schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;          schp.sched_priority = sched_get_priority_max(policy) + this->PriorityDelta;
186      }      }
187      if (this->PriorityMax == -1) {      if (this->PriorityMax == -1) {
188          schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;          schp.sched_priority = sched_get_priority_min(policy) + this->PriorityDelta;
189      }      }
190        if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
191      if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {          std::cerr << "Thread: WARNING, can't assign "
192          perror("Thread: WARNING, can't assign realtime scheduling to thread!");                    << policyDescription
193                      << " scheduling to thread!"
194                      << std::endl << std::flush;
195          return -1;          return -1;
196      }      }
197  #endif  #endif
# Line 166  int Thread::LockMemory() { Line 205  int Thread::LockMemory() {
205  #if !defined(__APPLE__)  #if !defined(__APPLE__)
206      if (!bLockedMemory) return 0;      if (!bLockedMemory) return 0;
207      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
208          perror("Thread: WARNING, can't mlockall() memory!");          std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
209                      << std::flush;
210          return -1;          return -1;
211      }      }
212  #endif  #endif
# Line 180  int Thread::LockMemory() { Line 220  int Thread::LockMemory() {
220   *  CALL THIS METHOD YOURSELF!   *  CALL THIS METHOD YOURSELF!
221   */   */
222  void Thread::EnableDestructor() {  void Thread::EnableDestructor() {
223      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
224      pthread_key_create(&__thread_destructor_key, __pthread_destructor);      pthread_key_create(&__thread_destructor_key, __pthread_destructor);
225      pthread_setspecific(__thread_destructor_key, this);      pthread_setspecific(__thread_destructor_key, this);
226      Running = true;      RunningCondition.Set(true);
227      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
     pthread_cond_broadcast(&__thread_start_condition);  
228  }  }
229    
230  /**  /**
# Line 193  void Thread::EnableDestructor() { Line 232  void Thread::EnableDestructor() {
232   */   */
233  int Thread::Destructor() {  int Thread::Destructor() {
234      pthread_key_delete(__thread_destructor_key);      pthread_key_delete(__thread_destructor_key);
235      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Set(false);
     Running = false;  
     pthread_mutex_unlock(&__thread_state_mutex);  
     pthread_cond_broadcast(&__thread_exit_condition);  
236      return 0;      return 0;
237  }  }
238    

Legend:
Removed from v.1220  
changed lines
  Added in v.1221

  ViewVC Help
Powered by ViewVC