]> git.mxchange.org Git - simgear.git/blob - simgear/threads/SGThread.cxx
Add another subsystem group.
[simgear.git] / simgear / threads / SGThread.cxx
1 // SGThread - Simple pthread class wrappers.
2 //
3 // Written by Bernie Bright, started April 2001.
4 //
5 // Copyright (C) 2001  Bernard Bright - bbright@bigpond.net.au
6 // Copyright (C) 2011  Mathias Froehlich
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22
23 #ifdef HAVE_CONFIG_H
24 # include <simgear_config.h>
25 #endif
26
27 #include <simgear/compiler.h>
28
29 #include "SGThread.hxx"
30
31 #ifdef _WIN32
32
33 /////////////////////////////////////////////////////////////////////////////
34 /// win32 threads
35 /////////////////////////////////////////////////////////////////////////////
36
37 #include <list>
38 #include <windows.h>
39
40 struct SGThread::PrivateData {
41     PrivateData() :
42         _handle(INVALID_HANDLE_VALUE)
43     {
44     }
45     ~PrivateData()
46     {
47         if (_handle == INVALID_HANDLE_VALUE)
48             return;
49         CloseHandle(_handle);
50         _handle = INVALID_HANDLE_VALUE;
51     }
52
53     static DWORD WINAPI start_routine(LPVOID data)
54     {
55         SGThread* thread = reinterpret_cast<SGThread*>(data);
56         thread->run();
57         return 0;
58     }
59
60     bool start(SGThread& thread)
61     {
62         if (_handle != INVALID_HANDLE_VALUE)
63             return false;
64         _handle = CreateThread(0, 0, start_routine, &thread, 0, 0);
65         if (_handle == INVALID_HANDLE_VALUE)
66             return false;
67         return true;
68     }
69
70     void join()
71     {
72         if (_handle == INVALID_HANDLE_VALUE)
73             return;
74         DWORD ret = WaitForSingleObject(_handle, INFINITE);
75         if (ret != WAIT_OBJECT_0)
76             return;
77         CloseHandle(_handle);
78         _handle = INVALID_HANDLE_VALUE;
79     }
80
81     HANDLE _handle;
82 };
83
84 struct SGMutex::PrivateData {
85     PrivateData()
86     {
87         InitializeCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
88     }
89
90     ~PrivateData()
91     {
92         DeleteCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
93     }
94
95     void lock(void)
96     {
97         EnterCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
98     }
99
100     void unlock(void)
101     {
102         LeaveCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
103     }
104
105     CRITICAL_SECTION _criticalSection;
106 };
107
108 struct SGWaitCondition::PrivateData {
109     ~PrivateData(void)
110     {
111         // The waiters list should be empty anyway
112         _mutex.lock();
113         while (!_pool.empty()) {
114             CloseHandle(_pool.front());
115             _pool.pop_front();
116         }
117         _mutex.unlock();
118     }
119
120     void signal(void)
121     {
122         _mutex.lock();
123         if (!_waiters.empty())
124             SetEvent(_waiters.back());
125         _mutex.unlock();
126     }
127
128     void broadcast(void)
129     {
130         _mutex.lock();
131         for (std::list<HANDLE>::iterator i = _waiters.begin(); i != _waiters.end(); ++i)
132             SetEvent(*i);
133         _mutex.unlock();
134     }
135
136     bool wait(SGMutex::PrivateData& externalMutex, DWORD msec)
137     {
138         _mutex.lock();
139         if (_pool.empty())
140             _waiters.push_front(CreateEvent(NULL, FALSE, FALSE, NULL));
141         else
142             _waiters.splice(_waiters.begin(), _pool, _pool.begin());
143         std::list<HANDLE>::iterator i = _waiters.begin();
144         _mutex.unlock();
145
146         externalMutex.unlock();
147
148         DWORD result = WaitForSingleObject(*i, msec);
149
150         externalMutex.lock();
151
152         _mutex.lock();
153         if (result != WAIT_OBJECT_0)
154             result = WaitForSingleObject(*i, 0);
155         _pool.splice(_pool.begin(), _waiters, i);
156         _mutex.unlock();
157
158         return result == WAIT_OBJECT_0;
159     }
160
161     void wait(SGMutex::PrivateData& externalMutex)
162     {
163         wait(externalMutex, INFINITE);
164     }
165
166     // Protect the list of waiters
167     SGMutex::PrivateData _mutex;
168
169     std::list<HANDLE> _waiters;
170     std::list<HANDLE> _pool;
171 };
172
173 #else
174 /////////////////////////////////////////////////////////////////////////////
175 /// posix threads
176 /////////////////////////////////////////////////////////////////////////////
177
178 #include <pthread.h>
179 #include <cassert>
180 #include <cerrno>
181 #include <sys/time.h>
182
183 struct SGThread::PrivateData {
184     PrivateData() :
185         _started(false)
186     {
187     }
188     ~PrivateData()
189     {
190         // If we are still having a started thread and nobody waited,
191         // now detach ...
192         if (!_started)
193             return;
194         pthread_detach(_thread);
195     }
196
197     static void *start_routine(void* data)
198     {
199         SGThread* thread = reinterpret_cast<SGThread*>(data);
200         thread->run();
201         return 0;
202     }
203
204     bool start(SGThread& thread)
205     {
206         if (_started)
207             return false;
208
209         int ret = pthread_create(&_thread, 0, start_routine, &thread);
210         if (0 != ret)
211             return false;
212
213         _started = true;
214         return true;
215     }
216
217     void join()
218     {
219         if (!_started)
220             return;
221
222         pthread_join(_thread, 0);
223         _started = false;
224     }
225
226     pthread_t _thread;
227     bool _started;
228 };
229
230 struct SGMutex::PrivateData {
231     PrivateData()
232     {
233         int err = pthread_mutex_init(&_mutex, 0);
234         assert(err == 0);
235         (void)err;
236     }
237
238     ~PrivateData()
239     {
240         int err = pthread_mutex_destroy(&_mutex);
241         assert(err == 0);
242         (void)err;
243     }
244
245     void lock(void)
246     {
247         int err = pthread_mutex_lock(&_mutex);
248         assert(err == 0);
249         (void)err;
250     }
251
252     void unlock(void)
253     {
254         int err = pthread_mutex_unlock(&_mutex);
255         assert(err == 0);
256         (void)err;
257     }
258
259     pthread_mutex_t _mutex;
260 };
261
262 struct SGWaitCondition::PrivateData {
263     PrivateData(void)
264     {
265         int err = pthread_cond_init(&_condition, NULL);
266         assert(err == 0);
267         (void)err;
268     }
269     ~PrivateData(void)
270     {
271         int err = pthread_cond_destroy(&_condition);
272         assert(err == 0);
273         (void)err;
274     }
275
276     void signal(void)
277     {
278         int err = pthread_cond_signal(&_condition);
279         assert(err == 0);
280         (void)err;
281     }
282
283     void broadcast(void)
284     {
285         int err = pthread_cond_broadcast(&_condition);
286         assert(err == 0);
287         (void)err;
288     }
289
290     void wait(SGMutex::PrivateData& mutex)
291     {
292         int err = pthread_cond_wait(&_condition, &mutex._mutex);
293         assert(err == 0);
294         (void)err;
295     }
296
297     bool wait(SGMutex::PrivateData& mutex, unsigned msec)
298     {
299         struct timespec ts;
300 #ifdef HAVE_CLOCK_GETTIME
301         if (0 != clock_gettime(CLOCK_REALTIME, &ts))
302             return false;
303 #else
304         struct timeval tv;
305         if (0 != gettimeofday(&tv, NULL))
306             return false;
307         ts.tv_sec = tv.tv_sec;
308         ts.tv_nsec = tv.tv_usec * 1000;
309 #endif
310
311         ts.tv_nsec += 1000000*(msec % 1000);
312         if (1000000000 <= ts.tv_nsec) {
313             ts.tv_nsec -= 1000000000;
314             ts.tv_sec += 1;
315         }
316         ts.tv_sec += msec / 1000;
317
318         int evalue = pthread_cond_timedwait(&_condition, &mutex._mutex, &ts);
319         if (evalue == 0)
320           return true;
321
322         assert(evalue == ETIMEDOUT);
323         return false;
324     }
325
326     pthread_cond_t _condition;
327 };
328
329 #endif
330
331 SGThread::SGThread() :
332     _privateData(new PrivateData)
333 {
334 }
335
336 SGThread::~SGThread()
337 {
338     delete _privateData;
339     _privateData = 0;
340 }
341
342 bool
343 SGThread::start()
344 {
345     return _privateData->start(*this);
346 }
347
348 void
349 SGThread::join()
350 {
351     _privateData->join();
352 }
353
354 SGMutex::SGMutex() :
355     _privateData(new PrivateData)
356 {
357 }
358
359 SGMutex::~SGMutex()
360 {
361     delete _privateData;
362     _privateData = 0;
363 }
364
365 void
366 SGMutex::lock()
367 {
368     _privateData->lock();
369 }
370
371 void
372 SGMutex::unlock()
373 {
374     _privateData->unlock();
375 }
376
377 SGWaitCondition::SGWaitCondition() :
378     _privateData(new PrivateData)
379 {
380 }
381
382 SGWaitCondition::~SGWaitCondition()
383 {
384     delete _privateData;
385     _privateData = 0;
386 }
387
388 void
389 SGWaitCondition::wait(SGMutex& mutex)
390 {
391     _privateData->wait(*mutex._privateData);
392 }
393
394 bool
395 SGWaitCondition::wait(SGMutex& mutex, unsigned msec)
396 {
397     return _privateData->wait(*mutex._privateData, msec);
398 }
399
400 void
401 SGWaitCondition::signal()
402 {
403     _privateData->signal();
404 }
405
406 void
407 SGWaitCondition::broadcast()
408 {
409     _privateData->broadcast();
410 }