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 long SGThread::current( void ) {
85 return (long)GetCurrentThreadId();
88 struct SGMutex::PrivateData {
91 InitializeCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
96 DeleteCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
101 EnterCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
106 LeaveCriticalSection((LPCRITICAL_SECTION)&_criticalSection);
109 CRITICAL_SECTION _criticalSection;
112 struct SGWaitCondition::PrivateData {
115 // The waiters list should be empty anyway
117 while (!_pool.empty()) {
118 CloseHandle(_pool.front());
127 if (!_waiters.empty())
128 SetEvent(_waiters.back());
135 for (std::list<HANDLE>::iterator i = _waiters.begin(); i != _waiters.end(); ++i)
140 bool wait(SGMutex::PrivateData& externalMutex, DWORD msec)
144 _waiters.push_front(CreateEvent(NULL, FALSE, FALSE, NULL));
146 _waiters.splice(_waiters.begin(), _pool, _pool.begin());
147 std::list<HANDLE>::iterator i = _waiters.begin();
150 externalMutex.unlock();
152 DWORD result = WaitForSingleObject(*i, msec);
154 externalMutex.lock();
157 if (result != WAIT_OBJECT_0)
158 result = WaitForSingleObject(*i, 0);
159 _pool.splice(_pool.begin(), _waiters, i);
162 return result == WAIT_OBJECT_0;
165 void wait(SGMutex::PrivateData& externalMutex)
167 wait(externalMutex, INFINITE);
170 // Protect the list of waiters
171 SGMutex::PrivateData _mutex;
173 std::list<HANDLE> _waiters;
174 std::list<HANDLE> _pool;
178 /////////////////////////////////////////////////////////////////////////////
180 /////////////////////////////////////////////////////////////////////////////
185 #include <sys/time.h>
187 struct SGThread::PrivateData {
194 // If we are still having a started thread and nobody waited,
198 pthread_detach(_thread);
201 static void *start_routine(void* data)
203 SGThread* thread = reinterpret_cast<SGThread*>(data);
208 bool start(SGThread& thread)
213 int ret = pthread_create(&_thread, 0, start_routine, &thread);
226 pthread_join(_thread, 0);
234 long SGThread::current( void ) {
235 return (long)pthread_self();
238 struct SGMutex::PrivateData {
241 int err = pthread_mutex_init(&_mutex, 0);
248 int err = pthread_mutex_destroy(&_mutex);
255 int err = pthread_mutex_lock(&_mutex);
262 int err = pthread_mutex_unlock(&_mutex);
267 pthread_mutex_t _mutex;
270 struct SGWaitCondition::PrivateData {
273 int err = pthread_cond_init(&_condition, NULL);
279 int err = pthread_cond_destroy(&_condition);
286 int err = pthread_cond_signal(&_condition);
293 int err = pthread_cond_broadcast(&_condition);
298 void wait(SGMutex::PrivateData& mutex)
300 int err = pthread_cond_wait(&_condition, &mutex._mutex);
305 bool wait(SGMutex::PrivateData& mutex, unsigned msec)
308 #ifdef HAVE_CLOCK_GETTIME
309 if (0 != clock_gettime(CLOCK_REALTIME, &ts))
313 if (0 != gettimeofday(&tv, NULL))
315 ts.tv_sec = tv.tv_sec;
316 ts.tv_nsec = tv.tv_usec * 1000;
319 ts.tv_nsec += 1000000*(msec % 1000);
320 if (1000000000 <= ts.tv_nsec) {
321 ts.tv_nsec -= 1000000000;
324 ts.tv_sec += msec / 1000;
326 int evalue = pthread_cond_timedwait(&_condition, &mutex._mutex, &ts);
330 assert(evalue == ETIMEDOUT);
334 pthread_cond_t _condition;
339 SGThread::SGThread() :
340 _privateData(new PrivateData)
344 SGThread::~SGThread()
353 return _privateData->start(*this);
359 _privateData->join();
363 _privateData(new PrivateData)
376 _privateData->lock();
382 _privateData->unlock();
385 SGWaitCondition::SGWaitCondition() :
386 _privateData(new PrivateData)
390 SGWaitCondition::~SGWaitCondition()
397 SGWaitCondition::wait(SGMutex& mutex)
399 _privateData->wait(*mutex._privateData);
403 SGWaitCondition::wait(SGMutex& mutex, unsigned msec)
405 return _privateData->wait(*mutex._privateData, msec);
409 SGWaitCondition::signal()
411 _privateData->signal();
415 SGWaitCondition::broadcast()
417 _privateData->broadcast();