1 // SGThread - Simple pthread class wrappers.
3 // Written by Bernie Bright, started April 2001.
5 // Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
6 // Copyright (C) 2011 Mathias Froehlich
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.
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.
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.
24 # include <simgear_config.h>
27 #include <simgear/compiler.h>
29 #include "SGThread.hxx"
33 /////////////////////////////////////////////////////////////////////////////
35 /////////////////////////////////////////////////////////////////////////////
40 struct SGThread::PrivateData {
42 _handle(INVALID_HANDLE_VALUE)
47 if (_handle == INVALID_HANDLE_VALUE)
50 _handle = INVALID_HANDLE_VALUE;
53 static DWORD WINAPI start_routine(LPVOID data)
55 SGThread* thread = reinterpret_cast<SGThread*>(data);
60 bool start(SGThread& thread)
62 if (_handle != INVALID_HANDLE_VALUE)
64 _handle = CreateThread(0, 0, start_routine, &thread, 0, 0);
65 if (_handle == INVALID_HANDLE_VALUE)
72 if (_handle == INVALID_HANDLE_VALUE)
74 DWORD ret = WaitForSingleObject(_handle, INFINITE);
75 if (ret != WAIT_OBJECT_0)
78 _handle = INVALID_HANDLE_VALUE;
84 struct SGMutex::PrivateData {
87 InitializeCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
92 DeleteCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
97 EnterCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
102 LeaveCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
105 CRITICAL_SECTION _criticalSection;
108 struct SGWaitCondition::PrivateData {
111 // The waiters list should be empty anyway
113 while (!_pool.empty()) {
114 CloseHandle(_pool.front());
123 if (!_waiters.empty())
124 SetEvent(_waiters.back());
131 for (std::list<HANDLE>::iterator i = _waiters.begin(); i != _waiters.end(); ++i)
136 bool wait(SGMutex::PrivateData& externalMutex, DWORD msec)
140 _waiters.push_front(CreateEvent(NULL, FALSE, FALSE, NULL));
142 _waiters.splice(_waiters.begin(), _pool, _pool.begin());
143 std::list<HANDLE>::iterator i = _waiters.begin();
146 externalMutex.unlock();
148 DWORD result = WaitForSingleObject(*i, msec);
150 externalMutex.lock();
153 if (result != WAIT_OBJECT_0)
154 result = WaitForSingleObject(*i, 0);
155 _pool.splice(_pool.begin(), _waiters, i);
158 return result == WAIT_OBJECT_0;
161 void wait(SGMutex::PrivateData& externalMutex)
163 wait(externalMutex, INFINITE);
166 // Protect the list of waiters
167 SGMutex::PrivateData _mutex;
169 std::list<HANDLE> _waiters;
170 std::list<HANDLE> _pool;
174 /////////////////////////////////////////////////////////////////////////////
176 /////////////////////////////////////////////////////////////////////////////
181 #include <sys/time.h>
183 struct SGThread::PrivateData {
190 // If we are still having a started thread and nobody waited,
194 pthread_detach(_thread);
197 static void *start_routine(void* data)
199 SGThread* thread = reinterpret_cast<SGThread*>(data);
204 bool start(SGThread& thread)
209 int ret = pthread_create(&_thread, 0, start_routine, &thread);
222 pthread_join(_thread, 0);
230 struct SGMutex::PrivateData {
233 int err = pthread_mutex_init(&_mutex, 0);
240 int err = pthread_mutex_destroy(&_mutex);
247 int err = pthread_mutex_lock(&_mutex);
254 int err = pthread_mutex_unlock(&_mutex);
259 pthread_mutex_t _mutex;
262 struct SGWaitCondition::PrivateData {
265 int err = pthread_cond_init(&_condition, NULL);
271 int err = pthread_cond_destroy(&_condition);
278 int err = pthread_cond_signal(&_condition);
285 int err = pthread_cond_broadcast(&_condition);
290 void wait(SGMutex::PrivateData& mutex)
292 int err = pthread_cond_wait(&_condition, &mutex._mutex);
297 bool wait(SGMutex::PrivateData& mutex, unsigned msec)
300 #ifdef HAVE_CLOCK_GETTIME
301 if (0 != clock_gettime(CLOCK_REALTIME, &ts))
305 if (0 != gettimeofday(&tv, NULL))
307 ts.tv_sec = tv.tv_sec;
308 ts.tv_nsec = tv.tv_usec * 1000;
311 ts.tv_nsec += 1000000*(msec % 1000);
312 if (1000000000 <= ts.tv_nsec) {
313 ts.tv_nsec -= 1000000000;
316 ts.tv_sec += msec / 1000;
318 int evalue = pthread_cond_timedwait(&_condition, &mutex._mutex, &ts);
322 assert(evalue == ETIMEDOUT);
326 pthread_cond_t _condition;
331 SGThread::SGThread() :
332 _privateData(new PrivateData)
336 SGThread::~SGThread()
345 return _privateData->start(*this);
351 _privateData->join();
355 _privateData(new PrivateData)
368 _privateData->lock();
374 _privateData->unlock();
377 SGWaitCondition::SGWaitCondition() :
378 _privateData(new PrivateData)
382 SGWaitCondition::~SGWaitCondition()
389 SGWaitCondition::wait(SGMutex& mutex)
391 _privateData->wait(*mutex._privateData);
395 SGWaitCondition::wait(SGMutex& mutex, unsigned msec)
397 return _privateData->wait(*mutex._privateData, msec);
401 SGWaitCondition::signal()
403 _privateData->signal();
407 SGWaitCondition::broadcast()
409 _privateData->broadcast();