/[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 3289 by persson, Sun Oct 23 07:24:09 2016 UTC revision 3290 by schoenebeck, Fri Jun 23 12:24:58 2017 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                       *   *   Copyright (C) 2005 - 2017 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 27  Line 27 
27  # include <config.h>  # include <config.h>
28  #endif  #endif
29    
30    #if DEBUG
31    # include <assert.h>
32    #endif
33    
34  // this is the minimum stack size a thread will be spawned with  // this is the minimum stack size a thread will be spawned with
35  // if this value is too small, the OS will allocate memory on demand and  // if this value is too small, the OS will allocate memory on demand and
36  // thus might lead to dropouts in realtime threads  // thus might lead to dropouts in realtime threads
# Line 35  Line 39 
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
 #if defined(WIN32)  
 // Callback functions for the WIN32 thread API  
 DWORD WINAPI __win32thread_launcher(LPVOID lpParameter);  
 #else  
 // Callback functions for the POSIX thread API  
 static void* __pthread_launcher(void* thread);  
 static void  __pthread_destructor(void* thread);  
 #endif  
   
42  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {  Thread::Thread(bool LockMemory, bool RealTime, int PriorityMax, int PriorityDelta) {
43      this->bLockedMemory     = LockMemory;      this->bLockedMemory     = LockMemory;
44      this->isRealTime        = RealTime;      this->isRealTime        = RealTime;
45      this->PriorityDelta     = PriorityDelta;      this->PriorityDelta     = PriorityDelta;
46      this->PriorityMax       = PriorityMax;      this->PriorityMax       = PriorityMax;
47        this->state = NOT_RUNNING;
48  #if defined(WIN32)  #if defined(WIN32)
49  #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)  # if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
50      win32isRunning = false;      win32isRunning = false;
51  #endif  # endif
52  #else  #else
53      __thread_destructor_key = 0;      __thread_destructor_key = 0;
54      pthread_attr_init(&__thread_attr);      pthread_attr_init(&__thread_attr);
# Line 60  Thread::Thread(bool LockMemory, bool Rea Line 56  Thread::Thread(bool LockMemory, bool Rea
56  }  }
57    
58  Thread::~Thread() {  Thread::~Thread() {
59      StopThread();      // The thread must no longer be running at this point, otherwise it is an
60  #if defined(WIN32)      // error (we should avoid an implied call of StopThread() in the destructor,
61        // because trying to do so might cause undefined behavior).
62    #if DEBUG
63        assert(!RunningCondition.GetUnsafe());
64  #else  #else
65        if (RunningCondition.GetUnsafe()) {
66            std::cerr << "WARNING: Thread destructed while still running!\n" << std::flush;
67            StopThread();
68        }
69    #endif
70    #if !defined(WIN32)
71      pthread_attr_destroy(&__thread_attr);      pthread_attr_destroy(&__thread_attr);
72  #endif  #endif
73  }  }
74    
75  /**  /**
76   *  Starts the thread. This method will wait until the thread actually   *  Starts the thread synchronously. This method will block until the thread
77   *  started it's execution before it will return. The abstract method   *  actually started it's execution before it will return. The abstract method
78   *  Main() is the entry point for the new thread. You have to implement the   *  Main() is the entry point for the new thread. You have to implement the
79   *  Main() method in your subclass.   *  Main() method in your subclass.
80     *
81     *  If this thread is already running when this method is called, then this
82     *  method will detect this and return accordingly without further actions.
83     *
84     *  @returns   0 on success, any other value if thread could not be launched
85   */   */
86  int Thread::StartThread() {  int Thread::StartThread() {
87        int res = -1;
88  #if defined (WIN32_SIGNALSTARTTHREAD_WORKAROUND)  #if defined (WIN32_SIGNALSTARTTHREAD_WORKAROUND)
89      // poll the win32isRunning variable and sleep 1msec inbetween      // poll the win32isRunning variable and sleep 1msec inbetween
90      if(!win32isRunning) {      if(!win32isRunning) {
91          SignalStartThread();          res = SignalStartThread();
92          while(1) {          if (res == 0) {
93              Sleep(1);              while (true) {
94              if(win32isRunning) break;                  Sleep(1);
95                    if (win32isRunning) break;
96                }
97          }          }
98      }      } else res = 0;
     return 0;  
99  #else  #else
100      RunningCondition.Lock();      LockGuard g(RunningCondition);
101        // If the thread terminated on its own (i.e. returned from Main()) without
102        // any thread calling StopThread() yet, then the OS blocks termination of
103        // the thread waiting for a pthread_join() call. So we must detach the
104        // thread in this case, because otherwise it will cause a thread leak.
105        if (state == PENDING_JOIN) {
106            state = DETACHED;
107            #if !defined(WIN32)
108            pthread_detach(__thread_id);
109            #endif
110        }
111      if (!RunningCondition.GetUnsafe()) {      if (!RunningCondition.GetUnsafe()) {
112          SignalStartThread();          res = SignalStartThread();
113          // wait until thread started execution          // if thread was triggered successfully, wait until thread actually
114          RunningCondition.WaitIf(false);          // started execution
115            if (res == 0)
116                RunningCondition.PreLockedWaitIf(false);
117        } else {
118            res = 0;
119      }      }
     RunningCondition.Unlock();  
     return 0;  
120  #endif  #endif
121        return res;
122  }  }
123    
124  /**  /**
# Line 102  int Thread::StartThread() { Line 127  int Thread::StartThread() {
127   *  method returns! The abstract method Main() is the entry point for the   *  method returns! The abstract method Main() is the entry point for the
128   *  new thread. You have to implement the Main() method in your subclass.   *  new thread. You have to implement the Main() method in your subclass.
129   *   *
130     *  @b IMPORTANT: Calling this method assumes that this thread is not yet
131     *  running! Calling this method if the thread is already running causes
132     *  undefined behavior!
133     *
134   *  @see StartThread()   *  @see StartThread()
135   */   */
136  int Thread::SignalStartThread() {  int Thread::SignalStartThread() {
137        state = RUNNING;
138  #if defined(WIN32)  #if defined(WIN32)
139      LPVOID lpParameter;      LPVOID lpParameter;
140      hThread = CreateThread(      hThread = CreateThread(
141                 NULL, // no security attributes                 NULL, // no security attributes
142                 MIN_STACK_SIZE,                 MIN_STACK_SIZE,
143                 __win32thread_launcher,                 win32threadLauncher,
144                 this,                 this,
145                 0,                 0,
146                 &lpThreadId);                 &lpThreadId);
# Line 156  int Thread::SignalStartThread() { Line 186  int Thread::SignalStartThread() {
186      }      }
187    
188      // Create and run the thread      // Create and run the thread
189      res = pthread_create(&this->__thread_id, &__thread_attr, __pthread_launcher, this);      res = pthread_create(&this->__thread_id, &__thread_attr, pthreadLauncher, this);
190      switch (res) {      switch (res) {
191          case 0: // Success          case 0: // Success
192              break;              break;
# Line 181  int Thread::SignalStartThread() { Line 211  int Thread::SignalStartThread() {
211  }  }
212    
213  /**  /**
214   *  Stops the thread. This method will wait until the thread actually stopped   *  Stops the thread synchronously. This method will block until the thread
215   *  it's execution before it will return.   *  actually stopped its execution before it will return from this method.
216     *
217     *  If the thread is not running when calling this method, this will be detected
218     *  and the call will be ignored. So it is safe to call this method both if the
219     *  thread never started, as well as if the thread has already been stopped. And
220     *  in fact you should explicitly call StopThread() before the Thread object is
221     *  going to be destructured!
222     *
223     *  @see SignalStopThread()
224   */   */
225  int Thread::StopThread() {  int Thread::StopThread() {
226  #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)  #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
227      SignalStopThread();      SignalStopThread();
228      win32isRunning = false;      win32isRunning = false;
229      return 0;      return 0;
230  #endif  #else
231        // LockGuard cannot be used here, because this is a bit more tricky here
232      RunningCondition.Lock();      RunningCondition.Lock();
233        #if !defined(WIN32)
234        // if thread was calling StopThread() on itself
235        if (pthread_equal(__thread_id, pthread_self())) {
236            RunningCondition.PreLockedSet(false);
237            state = DETACHED;
238            pthread_detach(__thread_id);
239            RunningCondition.Unlock();
240            pthread_exit(NULL);
241        }
242        #endif
243        // if we are here, then any other thread called StopThread() but not the thread itself
244      if (RunningCondition.GetUnsafe()) {      if (RunningCondition.GetUnsafe()) {
245          SignalStopThread();          SignalStopThread();
246          // wait until thread stopped execution          // wait until thread stopped execution
247          RunningCondition.WaitIf(true);          RunningCondition.PreLockedWaitAndUnlockIf(true);
248          #if defined(WIN32)          #if !defined(WIN32)
249          #else                    pthread_join(__thread_id, NULL);
250            #endif
251            RunningCondition.Lock();
252        }
253        // If the thread terminated on its own (i.e. returned from Main()) without
254        // any thread calling StopThread() yet, then the OS blocks termination of
255        // the thread waiting for a pthread_join() call. So we must detach the
256        // thread in this case, because otherwise it will cause a thread leak.
257        if (state == PENDING_JOIN) {
258            state = DETACHED;
259            #if !defined(WIN32)
260          pthread_detach(__thread_id);          pthread_detach(__thread_id);
261          #endif                    #endif
262      }      }
263      RunningCondition.Unlock();      RunningCondition.Unlock();
264      return 0;      return 0;
265    #endif
266  }  }
267    
268  /**  /**
269   *  Stops the thread. This method will signal to stop the thread and return   *  Stops the thread asynchronously. This method will signal to stop the thread
270   *  immediately. Note that the thread might still run when this method   *  and return immediately. Note that due to this the thread might still run
271   *  returns!   *  when this method returns!
272     *
273     *  @b IMPORTANT: You @ MUST still call StopThread() before destructing the
274     *  Thread object, even if you called SignalStopThread() before and the thread
275     *  is no longer running! Otherwise this may lead to a thread leak!
276   *   *
277   *  @see StopThread()   *  @see StopThread()
278   */   */
# Line 230  int Thread::SignalStopThread() { Line 295  int Thread::SignalStopThread() {
295  }  }
296    
297  /**  /**
298   * Returns @c true in case the thread is currently running.   * Returns @c true in case the thread is currently running. This method does not
299     * block and returns immediately.
300     *
301     * Note that no synchronization is performed when calling this method. So the
302     * returned result is a very volatile information which must be processed with
303     * precautions, that is it may not be used for code that might cause a race
304     * condition.
305   */   */
306  bool Thread::IsRunning() {  bool Thread::IsRunning() {
307      #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)      #if defined(WIN32_SIGNALSTARTTHREAD_WORKAROUND)
# Line 337  int Thread::LockMemory() { Line 408  int Thread::LockMemory() {
408  /**  /**
409   *  Registers thread destructor callback function which will be executed when   *  Registers thread destructor callback function which will be executed when
410   *  the thread stops it's execution and sets the 'Running' flag to true. This   *  the thread stops it's execution and sets the 'Running' flag to true. This
411   *  method will be called by the __pthread_launcher callback function, DO NOT   *  method will be called by the pthreadLauncher callback function, DO NOT
412   *  CALL THIS METHOD YOURSELF!   *  CALL THIS METHOD YOURSELF!
413   */   */
414  void Thread::EnableDestructor() {  void Thread::EnableDestructor() {
# Line 345  void Thread::EnableDestructor() { Line 416  void Thread::EnableDestructor() {
416      win32isRunning = true;      win32isRunning = true;
417      return;          return;    
418  #endif  #endif
419      RunningCondition.Lock();      LockGuard g(RunningCondition);
420  #if defined(WIN32)  #if !defined(WIN32)
421  #else        pthread_key_create(&__thread_destructor_key, pthreadDestructor);
     pthread_key_create(&__thread_destructor_key, __pthread_destructor);  
422      pthread_setspecific(__thread_destructor_key, this);      pthread_setspecific(__thread_destructor_key, this);
423  #endif    #endif
424      RunningCondition.Set(true);      RunningCondition.PreLockedSet(true);
     RunningCondition.Unlock();  
425  }  }
426    
427  /**  /**
428   *  Will be called by the kernel when the thread stops it's execution.   *  May be overridden by deriving classes to add additional custom cleanup
429     *  code if necessary for the event when thread terminates. Currently this
430     *  default implementation does nothing.
431   */   */
432  int Thread::Destructor() {  int Thread::onThreadEnd() {
 #if defined(WIN32)  
 #else  
     pthread_key_delete(__thread_destructor_key);  
     RunningCondition.Set(false);  
 #endif    
433      return 0;      return 0;
434  }  }
435    
436  void Thread::TestCancel() {  void Thread::TestCancel() {
437  #if CONFIG_PTHREAD_TESTCANCEL  #if !defined(WIN32)
438      pthread_testcancel();      pthread_testcancel();
439  #endif  #endif
440  }  }
# Line 378  void Thread::TestCancel() { Line 444  void Thread::TestCancel() {
444  // make sure stack is 16-byte aligned for SSE instructions  // make sure stack is 16-byte aligned for SSE instructions
445  __attribute__((force_align_arg_pointer))  __attribute__((force_align_arg_pointer))
446  #endif  #endif
447  DWORD WINAPI __win32thread_launcher(LPVOID lpParameter) {  DWORD WINAPI Thread::win32threadLauncher(LPVOID lpParameter) {
448      Thread* t;      Thread* t;
449      t = (Thread*) lpParameter;      t = (Thread*) lpParameter;
450      t->SetSchedulingPriority();      t->SetSchedulingPriority();
# Line 389  DWORD WINAPI __win32thread_launcher(LPVO Line 455  DWORD WINAPI __win32thread_launcher(LPVO
455  }  }
456  #else  #else
457  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
458  static void* __pthread_launcher(void* thread) {  void* Thread::pthreadLauncher(void* thread) {
459  #if !CONFIG_PTHREAD_TESTCANCEL  #if !CONFIG_PTHREAD_TESTCANCEL
460      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); // let the thread be killable under any circumstances      // let the thread be killable under any circumstances
461        if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
462            std::cerr << "Thread: WARNING, PTHREAD_CANCEL_ASYNCHRONOUS not supported!\n" << std::flush;
463        }
464  #endif  #endif
465        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
466      Thread* t;      Thread* t;
467      t = (Thread*) thread;      t = (Thread*) thread;
468      t->SetSchedulingPriority();      t->SetSchedulingPriority();
# Line 404  static void* __pthread_launcher(void* th Line 473  static void* __pthread_launcher(void* th
473  }  }
474  #endif  #endif
475    
476  #if defined(WIN32)  #if !defined(WIN32)
 #else  
477  /// Callback function for the POSIX thread API  /// Callback function for the POSIX thread API
478  static void __pthread_destructor(void* thread) {  void Thread::pthreadDestructor(void* thread) {
479      Thread* t;      Thread* t;
480      t = (Thread*) thread;      t = (Thread*) thread;
481      t->Destructor();      LockGuard g(t->RunningCondition);
482        t->onThreadEnd();
483        pthread_key_delete(t->__thread_destructor_key);
484        // inform that thread termination blocks waiting for pthread_join()
485        // (not detaching the thread here already, because otherwise this might lead
486        // to a data race of the vpointer with the Thread object destructor)
487        t->state = PENDING_JOIN;
488        t->RunningCondition.PreLockedSet(false);
489  }  }
490  #endif  #endif
491    

Legend:
Removed from v.3289  
changed lines
  Added in v.3290

  ViewVC Help
Powered by ViewVC