CPPMyth
Library to interoperate with MythTV server
thread.h
1 #pragma once
2 /*
3  * Copyright (C) 2015 Jean-Luc Barriere
4  *
5  * This library is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 3, or (at your option)
8  * any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; see the file COPYING. If not, write to
17  * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18  * MA 02110-1301 USA
19  * http://www.gnu.org/copyleft/gpl.html
20  *
21  */
22 
23 #include "mutex.h"
24 #include "condition.h"
25 
26 #ifdef NSROOT
27 namespace NSROOT {
28 #endif
29 namespace OS
30 {
31 
32  class CThread
33  {
34  public:
35  CThread()
36  : m_finalizeOnStop(false)
37  , m_handle(new Handle()) { }
38 
39  virtual ~CThread()
40  {
41  delete m_handle;
42  }
43 
44  CThread(const CThread& _thread)
45  {
46  this->m_handle = new Handle();
47  this->m_finalizeOnStop = _thread.m_finalizeOnStop;
48  }
49 
50  CThread& operator=(const CThread& _thread)
51  {
52  if (this != &_thread)
53  {
54  delete this->m_handle;
55  this->m_handle = new Handle();
56  this->m_finalizeOnStop = _thread.m_finalizeOnStop;
57  }
58  return *this;
59  }
60 
61  thread_t* NativeHandle()
62  {
63  return &(m_handle->nativeHandle);
64  }
65 
66  bool StartThread(bool wait = true)
67  {
68  CLockGuard lock(m_handle->mutex);
69  if (!m_handle->running)
70  {
71  m_handle->notifiedStop = false;
72  if (thread_create(&(m_handle->nativeHandle), CThread::ThreadHandler, ((void*)static_cast<CThread*>(this))))
73  {
74  if (wait)
75  m_handle->condition.Wait(m_handle->mutex, m_handle->running);
76  return true;
77  }
78  }
79  return false;
80  }
81 
82  void StopThread(bool wait = true)
83  {
84  // First signal stop
85  {
86  CLockGuard lock(m_handle->mutex);
87  m_handle->notifiedStop = true;
88  m_handle->condition.Broadcast();
89  }
90  // Waiting stopped
91  if (wait)
92  {
93  CLockGuard lock(m_handle->mutex);
94  m_handle->condition.Wait(m_handle->mutex, m_handle->stopped);
95  }
96  }
97 
98  bool WaitThread(unsigned timeout)
99  {
100  CLockGuard lock(m_handle->mutex);
101  return m_handle->stopped ? true : m_handle->condition.Wait(m_handle->mutex, m_handle->stopped, timeout);
102  }
103 
104  bool IsRunning()
105  {
106  CLockGuard lock(m_handle->mutex);
107  return m_handle->running;
108  }
109 
110  bool IsStopped()
111  {
112  CLockGuard lock(m_handle->mutex);
113  return m_handle->notifiedStop || m_handle->stopped;
114  }
115 
116  void Sleep(unsigned timeout)
117  {
118  CTimeout _timeout(timeout);
119  CLockGuard lock(m_handle->mutex);
120  while (!m_handle->notifiedStop && !m_handle->notifiedWake && m_handle->condition.Wait(m_handle->mutex, _timeout));
121  m_handle->notifiedWake = false; // Reset the wake flag
122  }
123 
124  void WakeUp()
125  {
126  CLockGuard lock(m_handle->mutex);
127  m_handle->notifiedWake = true;
128  m_handle->condition.Broadcast();
129  }
130 
131  protected:
132  virtual void* Process(void) = 0;
133  virtual void Finalize(void) { };
134  bool m_finalizeOnStop;
135 
136  private:
137  struct Handle
138  {
139  thread_t nativeHandle;
140  volatile bool running;
141  volatile bool stopped;
142  volatile bool notifiedStop;
143  volatile bool notifiedWake;
144  CCondition<volatile bool> condition;
145  CMutex mutex;
146 
147  Handle()
148  : nativeHandle(0)
149  , running(false)
150  , stopped(true)
151  , notifiedStop(false)
152  , notifiedWake(false)
153  , condition()
154  , mutex() { }
155  };
156 
157  Handle* m_handle;
158 
159  static void* ThreadHandler(void* _thread)
160  {
161  CThread* thread = static_cast<CThread*>(_thread);
162  void* ret = NULL;
163 
164  if (thread)
165  {
166  bool finalize = thread->m_finalizeOnStop;
167  {
168  CLockGuard lock(thread->m_handle->mutex);
169  thread->m_handle->running = true;
170  thread->m_handle->stopped = false;
171  thread->m_handle->condition.Broadcast();
172  lock.Unlock();
173  ret = thread->Process();
174  lock.Lock();
175  thread->m_handle->running = false;
176  thread->m_handle->stopped = true;
177  thread->m_handle->condition.Broadcast();
178  }
179  // Thread without finalizer could be freed here
180  if (finalize)
181  thread->Finalize();
182  }
183 
184  return ret;
185  }
186 
187  };
188 
189 }
190 #ifdef NSROOT
191 }
192 #endif