]> git.mxchange.org Git - simgear.git/blob - simgear/threads/SGThread.cxx
HTTP terra sync: fix hash cache handling
[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 long SGThread::current( void ) {
85     return (long)GetCurrentThreadId();
86 }
87
88 struct SGMutex::PrivateData {
89     PrivateData()
90     {
91         InitializeCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
92     }
93
94     ~PrivateData()
95     {
96         DeleteCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
97     }
98
99     void lock(void)
100     {
101         EnterCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
102     }
103
104     void unlock(void)
105     {
106         LeaveCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
107     }
108
109     CRITICAL_SECTION _criticalSection;
110 };
111
112 struct SGWaitCondition::PrivateData {
113     ~PrivateData(void)
114     {
115         // The waiters list should be empty anyway
116         _mutex.lock();
117         while (!_pool.empty()) {
118             CloseHandle(_pool.front());
119             _pool.pop_front();
120         }
121         _mutex.unlock();
122     }
123
124     void signal(void)
125     {
126         _mutex.lock();
127         if (!_waiters.empty())
128             SetEvent(_waiters.back());
129         _mutex.unlock();
130     }
131
132     void broadcast(void)
133     {
134         _mutex.lock();
135         for (std::list<HANDLE>::iterator i = _waiters.begin(); i != _waiters.end(); ++i)
136             SetEvent(*i);
137         _mutex.unlock();
138     }
139
140     bool wait(SGMutex::PrivateData& externalMutex, DWORD msec)
141     {
142         _mutex.lock();
143         if (_pool.empty())
144             _waiters.push_front(CreateEvent(NULL, FALSE, FALSE, NULL));
145         else
146             _waiters.splice(_waiters.begin(), _pool, _pool.begin());
147         std::list<HANDLE>::iterator i = _waiters.begin();
148         _mutex.unlock();
149
150         externalMutex.unlock();
151
152         DWORD result = WaitForSingleObject(*i, msec);
153
154         externalMutex.lock();
155
156         _mutex.lock();
157         if (result != WAIT_OBJECT_0)
158             result = WaitForSingleObject(*i, 0);
159         _pool.splice(_pool.begin(), _waiters, i);
160         _mutex.unlock();
161
162         return result == WAIT_OBJECT_0;
163     }
164
165     void wait(SGMutex::PrivateData& externalMutex)
166     {
167         wait(externalMutex, INFINITE);
168     }
169
170     // Protect the list of waiters
171     SGMutex::PrivateData _mutex;
172
173     std::list<HANDLE> _waiters;
174     std::list<HANDLE> _pool;
175 };
176
177 #else
178 /////////////////////////////////////////////////////////////////////////////
179 /// posix threads
180 /////////////////////////////////////////////////////////////////////////////
181
182 #include <pthread.h>
183 #include <cassert>
184 #include <cerrno>
185 #include <sys/time.h>
186
187 struct SGThread::PrivateData {
188     PrivateData() :
189         _started(false)
190     {
191     }
192     ~PrivateData()
193     {
194         // If we are still having a started thread and nobody waited,
195         // now detach ...
196         if (!_started)
197             return;
198         pthread_detach(_thread);
199     }
200
201     static void *start_routine(void* data)
202     {
203         SGThread* thread = reinterpret_cast<SGThread*>(data);
204         thread->run();
205         return 0;
206     }
207
208     bool start(SGThread& thread)
209     {
210         if (_started)
211             return false;
212
213         int ret = pthread_create(&_thread, 0, start_routine, &thread);
214         if (0 != ret)
215             return false;
216
217         _started = true;
218         return true;
219     }
220
221     void join()
222     {
223         if (!_started)
224             return;
225
226         pthread_join(_thread, 0);
227         _started = false;
228     }
229
230     pthread_t _thread;
231     bool _started;
232 };
233
234 long SGThread::current( void ) {
235     return (long)pthread_self();
236 }
237
238 struct SGMutex::PrivateData {
239     PrivateData()
240     {
241         int err = pthread_mutex_init(&_mutex, 0);
242         assert(err == 0);
243         (void)err;
244     }
245
246     ~PrivateData()
247     {
248         int err = pthread_mutex_destroy(&_mutex);
249         assert(err == 0);
250         (void)err;
251     }
252
253     void lock(void)
254     {
255         int err = pthread_mutex_lock(&_mutex);
256         assert(err == 0);
257         (void)err;
258     }
259
260     void unlock(void)
261     {
262         int err = pthread_mutex_unlock(&_mutex);
263         assert(err == 0);
264         (void)err;
265     }
266
267     pthread_mutex_t _mutex;
268 };
269
270 struct SGWaitCondition::PrivateData {
271     PrivateData(void)
272     {
273         int err = pthread_cond_init(&_condition, NULL);
274         assert(err == 0);
275         (void)err;
276     }
277     ~PrivateData(void)
278     {
279         int err = pthread_cond_destroy(&_condition);
280         assert(err == 0);
281         (void)err;
282     }
283
284     void signal(void)
285     {
286         int err = pthread_cond_signal(&_condition);
287         assert(err == 0);
288         (void)err;
289     }
290
291     void broadcast(void)
292     {
293         int err = pthread_cond_broadcast(&_condition);
294         assert(err == 0);
295         (void)err;
296     }
297
298     void wait(SGMutex::PrivateData& mutex)
299     {
300         int err = pthread_cond_wait(&_condition, &mutex._mutex);
301         assert(err == 0);
302         (void)err;
303     }
304
305     bool wait(SGMutex::PrivateData& mutex, unsigned msec)
306     {
307         struct timespec ts;
308 #ifdef HAVE_CLOCK_GETTIME
309         if (0 != clock_gettime(CLOCK_REALTIME, &ts))
310             return false;
311 #else
312         struct timeval tv;
313         if (0 != gettimeofday(&tv, NULL))
314             return false;
315         ts.tv_sec = tv.tv_sec;
316         ts.tv_nsec = tv.tv_usec * 1000;
317 #endif
318
319         ts.tv_nsec += 1000000*(msec % 1000);
320         if (1000000000 <= ts.tv_nsec) {
321             ts.tv_nsec -= 1000000000;
322             ts.tv_sec += 1;
323         }
324         ts.tv_sec += msec / 1000;
325
326         int evalue = pthread_cond_timedwait(&_condition, &mutex._mutex, &ts);
327         if (evalue == 0)
328           return true;
329
330         assert(evalue == ETIMEDOUT);
331         return false;
332     }
333
334     pthread_cond_t _condition;
335 };
336
337 #endif
338
339 SGThread::SGThread() :
340     _privateData(new PrivateData)
341 {
342 }
343
344 SGThread::~SGThread()
345 {
346     delete _privateData;
347     _privateData = 0;
348 }
349
350 bool
351 SGThread::start()
352 {
353     return _privateData->start(*this);
354 }
355
356 void
357 SGThread::join()
358 {
359     _privateData->join();
360 }
361
362 SGMutex::SGMutex() :
363     _privateData(new PrivateData)
364 {
365 }
366
367 SGMutex::~SGMutex()
368 {
369     delete _privateData;
370     _privateData = 0;
371 }
372
373 void
374 SGMutex::lock()
375 {
376     _privateData->lock();
377 }
378
379 void
380 SGMutex::unlock()
381 {
382     _privateData->unlock();
383 }
384
385 SGWaitCondition::SGWaitCondition() :
386     _privateData(new PrivateData)
387 {
388 }
389
390 SGWaitCondition::~SGWaitCondition()
391 {
392     delete _privateData;
393     _privateData = 0;
394 }
395
396 void
397 SGWaitCondition::wait(SGMutex& mutex)
398 {
399     _privateData->wait(*mutex._privateData);
400 }
401
402 bool
403 SGWaitCondition::wait(SGMutex& mutex, unsigned msec)
404 {
405     return _privateData->wait(*mutex._privateData, msec);
406 }
407
408 void
409 SGWaitCondition::signal()
410 {
411     _privateData->signal();
412 }
413
414 void
415 SGWaitCondition::broadcast()
416 {
417     _privateData->broadcast();
418 }