fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / Base / Threading / OSGCondVar.cpp
blob817c508c70ba4dc815faacd9ecb8b13d01cf6d0a
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2003 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 #include <cstdlib>
40 #include <cstdio>
42 // If we are on windows and not WinCE, then target Windows NT 4.0
43 #if defined (WIN32) && !defined(_WIN32_WINNT) && !defined(_WIN32_WCE)
44 #define _WIN32_WINNT 0x0400
45 #endif
47 #include "OSGConfig.h"
49 #include <iostream>
51 #include "OSGCondVar.h"
53 #include "OSGBaseFunctions.h"
55 #include "OSGThreadManager.h"
57 #include "OSGLog.h"
59 OSG_USING_NAMESPACE
61 //---------------------------------------------------------------------------
62 // Class
63 //---------------------------------------------------------------------------
65 /*--------------------------- Constructors --------------------------------*/
67 CondVarCommonBase::CondVarCommonBase(void) :
68 Inherited (NULL, true),
69 _uiCondVarId(0 )
73 CondVarCommonBase::CondVarCommonBase(const Char8 *szName,
74 UInt32 uiId,
75 bool bGlobal):
76 Inherited (szName,
77 bGlobal),
78 _uiCondVarId(uiId )
82 /*---------------------------- Destructor ---------------------------------*/
84 CondVarCommonBase::~CondVarCommonBase(void)
90 #if defined (OSG_USE_PTHREADS)
92 //---------------------------------------------------------------------------
93 // Class
94 //---------------------------------------------------------------------------
96 /*--------------------------- Constructors --------------------------------*/
98 PThreadCondVarBase::PThreadCondVarBase(void):
99 Inherited (),
100 _pLowLevelLock (),
101 _pLowLevelCondVar()
105 PThreadCondVarBase::PThreadCondVarBase(const Char8 *szName,
106 UInt32 uiId,
107 bool bGlobal) :
108 Inherited (szName,
109 uiId,
110 bGlobal),
111 _pLowLevelLock ( ),
112 _pLowLevelCondVar( )
116 /*---------------------------- Destructor ---------------------------------*/
118 PThreadCondVarBase::~PThreadCondVarBase(void)
122 /*--------------------------- Construction --------------------------------*/
124 bool PThreadCondVarBase::init(void)
126 pthread_mutexattr_t lockAttr;
128 pthread_mutexattr_init(&lockAttr);
130 pthread_mutexattr_settype(&lockAttr, PTHREAD_MUTEX_RECURSIVE);
132 pthread_mutex_init(&(_pLowLevelLock), &lockAttr);
134 // Initialize the condition variable.
135 pthread_cond_init(&(_pLowLevelCondVar), NULL);
137 return true;
140 /*--------------------------- Destruction ---------------------------------*/
142 void PThreadCondVarBase::shutdown(void)
144 pthread_mutex_destroy(&(_pLowLevelLock));
145 pthread_cond_destroy(&(_pLowLevelCondVar));
148 bool PThreadCondVarBase::wait(const Int32 timeToWait)
150 bool result(true);
152 // Wait indefinitely on the condition variable.
153 if(timeToWait < 0)
155 const int retcode = pthread_cond_wait(&(_pLowLevelCondVar), &(_pLowLevelLock));
157 // If pthread_cond_wait(3) returned non-zero status, then we throw
158 // an exception. Otherwise, we return true.
159 if(retcode != 0)
161 return false;
164 // Wait for no longer than the given timeout period to acquire the lock
165 // on the condition variable.
166 else
168 struct timeval now; // The current time
169 struct timespec abs_timeout; // The absolute time of the timeout
171 const UInt64 UsecsPerSec(1000000);
173 // Calculate the absolute time for wait timeout
174 gettimeofday(&now, NULL);
176 UInt64 abs_secs = now.tv_sec +
177 static_cast<long> (timeToWait / 1000);
178 UInt64 abs_usecs = now.tv_usec +
179 static_cast<long>((timeToWait % 1000) * 1000);
181 if(abs_usecs > UsecsPerSec) // Have extra seconds
183 abs_secs += abs_usecs / UsecsPerSec; // Get the number of seconds
184 abs_usecs = abs_usecs % UsecsPerSec;
187 abs_timeout.tv_sec = abs_secs;
188 abs_timeout.tv_nsec = 1000 * (abs_usecs);
189 OSG_ASSERT(abs_timeout.tv_nsec < Int64(UsecsPerSec * 1000) &&
190 "Nano seconds out of range (greater then one second).");
192 const int retcode = pthread_cond_timedwait(&(_pLowLevelCondVar),
193 &(_pLowLevelLock),
194 &abs_timeout);
196 // Successful completion: return true.
197 if( 0 == retcode )
199 result = true;
201 else
203 result = false;
207 return result;
211 #endif /* OSG_USE_PTHREADS */
214 #if defined (OSG_USE_SPROC)
216 //---------------------------------------------------------------------------
217 // Class
218 //---------------------------------------------------------------------------
220 /*--------------------------- Constructors --------------------------------*/
222 SprocCondVarBase::SprocCondVarBase(void):
223 Inherited ( ),
224 #ifdef OSG_SPROC_USE_LOCK
225 _pLowLevelLock(NULL)
226 #else
227 _pLowLevelSema(NULL)
228 #endif
232 SprocCondVarBase::SprocCondVarBase(const Char8 *szName,
233 UInt32 uiId ):
234 Inherited (szName, uiId),
235 _pLowLevelLock(NULL )
236 #ifdef OSG_SPROC_USE_LOCK
237 _pLowLevelLock(NULL )
238 #else
239 _pLowLevelSema(NULL )
240 #endif
244 /*---------------------------- Destructor ---------------------------------*/
246 SprocCondVarBase::~SprocCondVarBase(void)
250 /*--------------------------- Construction --------------------------------*/
252 bool SprocCondVarBase::init(void)
254 ThreadManager *pThreadManager = ThreadManager::the();
256 if(pThreadManager == NULL)
257 return false;
259 if(pThreadManager->getArena() == NULL)
260 return false;
262 #ifdef OSG_SPROC_USE_LOCK
263 _pLowLevelLock = usnewlock(pThreadManager->getArena());
265 if(_pLowLevelLock == NULL)
266 return false;
268 usinitlock(_pLowLevelLock);
270 #else
271 _pLowLevelSema = usnewsema(pThreadManager->getArena(), 1);
273 if(_pLowLevelSema == NULL)
274 return false;
276 usinitsema(_pLowLevelSema, 1);
277 usctlsema (_pLowLevelSema, CS_RECURSIVEON, NULL);
278 #endif
280 return true;
283 /*--------------------------- Destruction ---------------------------------*/
285 void SprocCondVarBase::shutdown(void)
287 ThreadManager *pThreadManager = ThreadManager::the();
289 if(pThreadManager == NULL)
290 return;
292 if(pThreadManager->getArena() == NULL)
293 return;
295 #ifdef OSG_SPROC_USE_LOCK
296 if(_pLowLevelLock != NULL)
298 usfreelock(_pLowLevelLock, pThreadManager->getArena());
300 _pLowLevelLock = NULL;
302 #else
303 if(_pLowLevelSema != NULL)
305 usfreesema(_pLowLevelSema, pThreadManager->getArena());
307 _pLowLevelSema = NULL;
309 #endif
312 /*------------------------------- CondVar ---------------------------------*/
314 #endif /* OSG_USE_SPROC */
318 #if defined (OSG_USE_WINTHREADS)
320 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
322 int pthread_cond_init(pthread_cond_t *cv, void *dummy)
324 cv->waiters_count_ = 0;
325 cv->was_broadcast_ = 0;
326 cv->sema_ = CreateSemaphore(NULL, // no security
327 0, // initially 0
328 0x7fffffff, // max count
329 NULL); // unnamed
330 InitializeCriticalSection(&cv->waiters_count_lock_);
331 cv->waiters_done_ = CreateEvent (NULL, // no security
332 FALSE, // auto-reset
333 FALSE, // non-signaled initially
334 NULL); // unnamed
335 return 0;
338 int pthread_cond_wait(pthread_cond_t *cv,
339 pthread_mutex_t *external_mutex)
341 // Avoid race conditions.
342 EnterCriticalSection(&cv->waiters_count_lock_);
343 cv->waiters_count_++;
344 LeaveCriticalSection(&cv->waiters_count_lock_);
346 // This call atomically releases the mutex and waits on the
347 // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
348 // are called by another thread.
349 ::SignalObjectAndWait(*external_mutex, cv->sema_, INFINITE, FALSE);
351 // Reacquire lock to avoid race conditions.
352 EnterCriticalSection(&cv->waiters_count_lock_);
354 // We're no longer waiting...
355 cv->waiters_count_--;
357 // Check to see if we're the last waiter after <pthread_cond_broadcast>.
358 int last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
360 LeaveCriticalSection(&cv->waiters_count_lock_);
362 // If we're the last waiter thread during this particular broadcast
363 // then let all the other threads proceed.
364 if(last_waiter)
366 // This call atomically signals the <waiters_done_> event and waits until
367 // it can acquire the <external_mutex>. This is required to ensure fairness.
368 ::SignalObjectAndWait(cv->waiters_done_, *external_mutex, INFINITE, FALSE);
370 else
372 // Always regain the external mutex since that's the guarantee we
373 // give to our callers.
374 //WaitForSingleObject (*external_mutex);
375 WaitForSingleObject(cv->waiters_done_, INFINITE);
378 return 0;
381 int pthread_cond_signal(pthread_cond_t *cv)
383 EnterCriticalSection(&cv->waiters_count_lock_);
384 int have_waiters = cv->waiters_count_ > 0;
385 LeaveCriticalSection(&cv->waiters_count_lock_);
387 // If there aren't any waiters, then this is a no-op.
388 if(have_waiters)
390 ReleaseSemaphore(cv->sema_, 1, 0);
392 return 0;
395 int pthread_cond_broadcast (pthread_cond_t *cv)
397 // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
398 // consistent relative to each other.
399 EnterCriticalSection(&cv->waiters_count_lock_);
400 int have_waiters = 0;
402 if(cv->waiters_count_ > 0)
404 // We are broadcasting, even if there is just one waiter...
405 // Record that we are broadcasting, which helps optimize
406 // <pthread_cond_wait> for the non-broadcast case.
407 cv->was_broadcast_ = 1;
408 have_waiters = 1;
411 if(have_waiters)
413 // Wake up all the waiters atomically.
414 ReleaseSemaphore(cv->sema_, cv->waiters_count_, 0);
416 LeaveCriticalSection(&cv->waiters_count_lock_);
418 // Wait for all the awakened threads to acquire the counting
419 // semaphore.
420 WaitForSingleObject(cv->waiters_done_, INFINITE);
421 // This assignment is okay, even without the <waiters_count_lock_> held
422 // because no other waiter threads can wake up to access it.
423 cv->was_broadcast_ = 0;
425 else
427 LeaveCriticalSection(&cv->waiters_count_lock_);
430 return 0;
433 #endif
435 //---------------------------------------------------------------------------
436 // Class
437 //---------------------------------------------------------------------------
439 /*--------------------------- Constructors --------------------------------*/
441 WinThreadCondVarBase::WinThreadCondVarBase(void) :
442 Inherited( )
443 , _pMutex (NULL)
447 WinThreadCondVarBase::WinThreadCondVarBase(const Char8 *szName,
448 UInt32 uiId,
449 bool bGlobal) :
450 Inherited(szName, uiId, bGlobal),
451 _pMutex (NULL )
455 /*---------------------------- Destructor ---------------------------------*/
457 WinThreadCondVarBase::~WinThreadCondVarBase(void)
461 /*-------------------------- Construction ---------------------------------*/
463 bool WinThreadCondVarBase::init(void)
465 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
466 _pMutex = CreateMutex(NULL, // no security attributes
467 FALSE, // initially not owned
468 _szName); // name of mutex
470 if(_pMutex == NULL)
472 return false;
475 waiters_count_ = 0;
476 was_broadcast_ = 0;
477 sema_ = CreateSemaphore(NULL, // no security
478 0, // initially 0
479 0x7fffffff, // max count
480 NULL); // unnamed
481 InitializeCriticalSection(&waiters_count_lock_);
482 waiters_done_ = CreateEvent(NULL, // no security
483 FALSE, // auto-reset
484 FALSE, // non-signaled initially
485 NULL); // unnamed
486 return true;
487 #else
488 OSG_ASSERT(false && "CondVar::init() Not implemented for versions of Windows < 4.0");
489 return false;
490 #endif
493 bool WinThreadCondVarBase::wait(const Int32 timeToWait)
495 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
496 // Avoid race conditions.
497 EnterCriticalSection (&waiters_count_lock_);
498 waiters_count_++;
499 LeaveCriticalSection (&waiters_count_lock_);
501 // This call atomically releases the mutex and waits on the
502 // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
503 // are called by another thread.
504 SignalObjectAndWait(_pMutex, sema_, INFINITE, FALSE);
506 // Reacquire lock to avoid race conditions.
507 EnterCriticalSection(&waiters_count_lock_);
509 // We're no longer waiting...
510 waiters_count_--;
512 // Check to see if we're the last waiter after <pthread_cond_broadcast>.
513 int last_waiter = was_broadcast_ && waiters_count_ == 0;
515 LeaveCriticalSection(&waiters_count_lock_);
517 // XXX: Need to use timeToWait.
519 // If we're the last waiter thread during this particular broadcast
520 // then let all the other threads proceed.
521 if(last_waiter)
523 // This call atomically signals the <waiters_done_> event and waits until
524 // it can acquire the <external_mutex>. This is required to ensure fairness.
525 SignalObjectAndWait(waiters_done_, _pMutex, INFINITE, FALSE);
527 else
529 // Always regain the external mutex since that's the guarantee we
530 // give to our callers.
531 WaitForSingleObject(_pMutex, INFINITE);
533 #else
534 OSG_ASSERT(false && "CondVar::wait() Not implemented for versions of Windows < 4.0");
535 #endif
536 return 0;
539 void WinThreadCondVarBase::signal()
541 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
542 EnterCriticalSection(&waiters_count_lock_);
543 int have_waiters = waiters_count_ > 0;
544 LeaveCriticalSection(&waiters_count_lock_);
546 // If there aren't any waiters, then this is a no-op.
547 if(have_waiters)
549 ReleaseSemaphore(sema_, 1, 0);
551 #else
552 OSG_ASSERT(false && "CondVar::signal() Not implemented for versions of Windows < 4.0");
553 #endif
556 void WinThreadCondVarBase::broadcast()
558 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
559 // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
560 // consistent relative to each other.
561 EnterCriticalSection(&waiters_count_lock_);
562 int have_waiters = 0;
564 if(waiters_count_ > 0)
566 // We are broadcasting, even if there is just one waiter...
567 // Record that we are broadcasting, which helps optimize
568 // <pthread_cond_wait> for the non-broadcast case.
569 was_broadcast_ = 1;
570 have_waiters = 1;
573 if(have_waiters)
575 // Wake up all the waiters atomically.
576 ReleaseSemaphore(sema_, waiters_count_, 0);
578 LeaveCriticalSection(&waiters_count_lock_);
580 // Wait for all the awakened threads to acquire the counting
581 // semaphore.
582 WaitForSingleObject(waiters_done_, INFINITE);
583 // This assignment is okay, even without the <waiters_count_lock_> held
584 // because no other waiter threads can wake up to access it.
585 was_broadcast_ = 0;
587 else
589 LeaveCriticalSection(&waiters_count_lock_);
591 #else
592 OSG_ASSERT(false && "CondVar::broadcast() Not implemented for versions of Windows < 4.0");
593 #endif
596 /*-------------------------- Destruction ----------------------------------*/
598 void WinThreadCondVarBase::shutdown(void)
600 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
601 if(_pMutex != NULL)
603 CloseHandle(_pMutex);
605 if(sema_ != NULL)
607 CloseHandle(sema_);
609 DeleteCriticalSection(&waiters_count_lock_);
610 if(waiters_done_ != NULL)
612 CloseHandle(waiters_done_);
614 #else
615 OSG_ASSERT(false && "CondVar::shutdown() Not implemented for versions of Windows < 4.0");
616 #endif
619 #endif /* OSG_USE_WINTHREADS */
623 //---------------------------------------------------------------------------
624 // Class
625 //---------------------------------------------------------------------------
627 MPCondVarType CondVar::_type("OSGCondVar", "OSGMPBase", &CondVar::create);
629 /*------------------------------- Get -------------------------------------*/
631 CondVar::ObjTransitPtr CondVar::get(const Char8 *szName, bool bGlobal)
633 return ThreadManager::the()->getCondVar(szName, bGlobal, "OSGCondVar");
636 CondVar *CondVar::find(const Char8 *szName)
638 return ThreadManager::the()->findCondVar(szName);
642 /*------------------------------ Create -----------------------------------*/
644 CondVar *CondVar::create(const Char8 *szName, UInt32 uiId, bool bGlobal)
646 CondVar *returnValue = NULL;
648 returnValue = new CondVar(szName, uiId, bGlobal);
650 if(returnValue->init() == false)
652 delete returnValue;
653 returnValue = NULL;
656 return returnValue;
659 /*--------------------------- Constructors --------------------------------*/
661 CondVar::CondVar(void) :
662 Inherited()
666 CondVar::CondVar(const Char8 *szName, UInt32 uiId, bool bGlobal) :
667 Inherited(szName, uiId, bGlobal)
671 /*---------------------------- Destructor ---------------------------------*/
673 CondVar::~CondVar(void)
675 _bGlobal = false;
677 ThreadManager::the()->remove(this);
679 shutdown();