CPPMyth
Library to interoperate with MythTV server
Loading...
Searching...
No Matches
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
27namespace NSROOT {
28#endif
29namespace OS
30{
31
32 class Thread
33 {
34 public:
35 Thread()
36 : m_finalizeOnStop(false)
37 , m_handle(new Handle()) { }
38
39 virtual ~Thread()
40 {
41 delete m_handle;
42 }
43
44 Thread(const Thread& _thread)
45 {
46 this->m_handle = new Handle();
47 this->m_finalizeOnStop = _thread.m_finalizeOnStop;
48 }
49
50 Thread& operator=(const Thread& _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* native_handle()
62 {
63 return &(m_handle->nativeHandle);
64 }
65
66 bool start_thread(bool wait = true)
67 {
68 LockGuard lock(m_handle->mutex);
69 if (!m_handle->running)
70 {
71 m_handle->notifiedStop = false;
72 if (thread_create(&(m_handle->nativeHandle), Thread::ThreadHandler, ((void*)static_cast<Thread*>(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 stop_thread(bool wait = true)
83 {
84 // First signal stop
85 {
86 LockGuard lock(m_handle->mutex);
87 m_handle->notifiedStop = true;
88 m_handle->condition.notify_all();
89 }
90 // Waiting stopped
91 if (wait)
92 {
93 LockGuard lock(m_handle->mutex);
94 m_handle->condition.wait(m_handle->mutex, m_handle->stopped);
95 }
96 }
97
98 bool wait_thread(unsigned millisec)
99 {
100 LockGuard lock(m_handle->mutex);
101 return m_handle->stopped ? true : m_handle->condition.wait_for(m_handle->mutex, millisec, m_handle->stopped);
102 }
103
104 bool is_running()
105 {
106 LockGuard lock(m_handle->mutex);
107 return m_handle->running;
108 }
109
110 bool is_stopped()
111 {
112 LockGuard lock(m_handle->mutex);
113 return m_handle->notifiedStop || m_handle->stopped;
114 }
115
116 void pause(unsigned millisec)
117 {
118 Timeout _timeout(millisec);
119 LockGuard lock(m_handle->mutex);
120 while (!m_handle->notifiedStop && !m_handle->notifiedWake && m_handle->condition.wait_for(m_handle->mutex, _timeout));
121 m_handle->notifiedWake = false; // Reset the wake flag
122 }
123
124 void wake()
125 {
126 LockGuard lock(m_handle->mutex);
127 m_handle->notifiedWake = true;
128 m_handle->condition.notify_all();
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 Condition<volatile bool> condition;
145 Mutex 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 Thread* thread = static_cast<Thread*>(_thread);
162 void* ret = nullptr;
163
164 if (thread)
165 {
166 bool finalize = thread->m_finalizeOnStop;
167 thread->m_handle->mutex.lock();
168 thread->m_handle->running = true;
169 thread->m_handle->stopped = false;
170 thread->m_handle->condition.notify_all();
171 thread->m_handle->mutex.unlock();
172 ret = thread->process();
173 thread->m_handle->mutex.lock();
174 thread->m_handle->running = false;
175 thread->m_handle->stopped = true;
176 thread->m_handle->condition.notify_all();
177 thread->m_handle->mutex.unlock();
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