/[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 392 by schoenebeck, Sat Feb 19 02:40:24 2005 UTC revision 1222 by persson, Sun Jun 10 06:54:54 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  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 48  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 66  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 95  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 113  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  }  }
155    
156  /**  /**
157     * Returns @c true in case the thread is currently running.
158     */
159    bool Thread::IsRunning() {
160        return RunningCondition.GetUnsafe();
161    }
162    
163    /**
164   *  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,
165   *  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
166   *  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 169  int Thread::SignalStopThread() {
169   */   */
170  int Thread::SetSchedulingPriority() {  int Thread::SetSchedulingPriority() {
171  #if !defined(__APPLE__)  #if !defined(__APPLE__)
172        int policy;
173        const 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 (isRealTime) { // it is not possible to change priority for the SCHED_OTHER policy
185          schp.sched_priority = sched_get_priority_max(SCHED_FIFO) + this->PriorityDelta;          if (this->PriorityMax == 1) {
186                schp.sched_priority = sched_get_priority_max(policy) + this->PriorityDelta;
187            }
188            if (this->PriorityMax == -1) {
189                schp.sched_priority = sched_get_priority_min(policy) + this->PriorityDelta;
190            }
191      }      }
192      if (this->PriorityMax == -1) {      if (pthread_setschedparam(__thread_id, policy, &schp) != 0) {
193          schp.sched_priority = sched_get_priority_min(SCHED_FIFO) + this->PriorityDelta;          std::cerr << "Thread: WARNING, can't assign "
194      }                    << policyDescription
195                      << " scheduling to thread!"
196      if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0) {                    << std::endl << std::flush;
         perror("Thread: WARNING, can't assign realtime scheduling to thread!");  
197          return -1;          return -1;
198      }      }
199  #endif  #endif
# Line 153  int Thread::SetSchedulingPriority() { Line 204  int Thread::SetSchedulingPriority() {
204   * Locks the memory so it will not be swapped out by the operating system.   * Locks the memory so it will not be swapped out by the operating system.
205   */   */
206  int Thread::LockMemory() {  int Thread::LockMemory() {
207    #if !defined(__APPLE__)
208      if (!bLockedMemory) return 0;      if (!bLockedMemory) return 0;
209      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {      if (mlockall(MCL_CURRENT | MCL_FUTURE) < 0) {
210          perror("Thread: WARNING, can't mlockall() memory!");          std::cerr << "Thread: WARNING, can't mlockall() memory!\n"
211                      << std::flush;
212          return -1;          return -1;
213      }      }
214    #endif
215      return 0;      return 0;
216  }  }
217    
# Line 168  int Thread::LockMemory() { Line 222  int Thread::LockMemory() {
222   *  CALL THIS METHOD YOURSELF!   *  CALL THIS METHOD YOURSELF!
223   */   */
224  void Thread::EnableDestructor() {  void Thread::EnableDestructor() {
225      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Lock();
226      pthread_key_create(&__thread_destructor_key, __pthread_destructor);      pthread_key_create(&__thread_destructor_key, __pthread_destructor);
227      pthread_setspecific(__thread_destructor_key, this);      pthread_setspecific(__thread_destructor_key, this);
228      Running = true;      RunningCondition.Set(true);
229      pthread_mutex_unlock(&__thread_state_mutex);      RunningCondition.Unlock();
     pthread_cond_broadcast(&__thread_start_condition);  
230  }  }
231    
232  /**  /**
# Line 181  void Thread::EnableDestructor() { Line 234  void Thread::EnableDestructor() {
234   */   */
235  int Thread::Destructor() {  int Thread::Destructor() {
236      pthread_key_delete(__thread_destructor_key);      pthread_key_delete(__thread_destructor_key);
237      pthread_mutex_lock(&__thread_state_mutex);      RunningCondition.Set(false);
238      Running = false;      return 0;
     pthread_mutex_unlock(&__thread_state_mutex);  
     pthread_cond_broadcast(&__thread_exit_condition);  
239  }  }
240    
241  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
# Line 196  void* __pthread_launcher(void* thread) { Line 247  void* __pthread_launcher(void* thread) {
247      t->LockMemory();      t->LockMemory();
248      t->EnableDestructor();      t->EnableDestructor();
249      t->Main();      t->Main();
250        return NULL;
251  }  }
252    
253  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
# Line 204  void __pthread_destructor(void* thread) Line 256  void __pthread_destructor(void* thread)
256      t = (Thread*) thread;      t = (Thread*) thread;
257      t->Destructor();      t->Destructor();
258  }  }
259    
260    } // namespace LinuxSampler

Legend:
Removed from v.392  
changed lines
  Added in v.1222

  ViewVC Help
Powered by ViewVC