1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2003 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
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
47 #include "OSGConfig.h"
51 #include "OSGCondVar.h"
53 #include "OSGBaseFunctions.h"
55 #include "OSGThreadManager.h"
61 //---------------------------------------------------------------------------
63 //---------------------------------------------------------------------------
65 /*--------------------------- Constructors --------------------------------*/
67 CondVarCommonBase::CondVarCommonBase(void) :
68 Inherited (NULL
, true),
73 CondVarCommonBase::CondVarCommonBase(const Char8
*szName
,
82 /*---------------------------- Destructor ---------------------------------*/
84 CondVarCommonBase::~CondVarCommonBase(void)
90 #if defined (OSG_USE_PTHREADS)
92 //---------------------------------------------------------------------------
94 //---------------------------------------------------------------------------
96 /*--------------------------- Constructors --------------------------------*/
98 PThreadCondVarBase::PThreadCondVarBase(void):
105 PThreadCondVarBase::PThreadCondVarBase(const Char8
*szName
,
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
);
140 /*--------------------------- Destruction ---------------------------------*/
142 void PThreadCondVarBase::shutdown(void)
144 pthread_mutex_destroy(&(_pLowLevelLock
));
145 pthread_cond_destroy(&(_pLowLevelCondVar
));
148 bool PThreadCondVarBase::wait(const Int32 timeToWait
)
152 // Wait indefinitely on the condition variable.
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.
164 // Wait for no longer than the given timeout period to acquire the lock
165 // on the condition variable.
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
),
196 // Successful completion: return true.
211 #endif /* OSG_USE_PTHREADS */
214 #if defined (OSG_USE_SPROC)
216 //---------------------------------------------------------------------------
218 //---------------------------------------------------------------------------
220 /*--------------------------- Constructors --------------------------------*/
222 SprocCondVarBase::SprocCondVarBase(void):
224 #ifdef OSG_SPROC_USE_LOCK
232 SprocCondVarBase::SprocCondVarBase(const Char8
*szName
,
234 Inherited (szName
, uiId
),
235 _pLowLevelLock(NULL
)
236 #ifdef OSG_SPROC_USE_LOCK
237 _pLowLevelLock(NULL
)
239 _pLowLevelSema(NULL
)
244 /*---------------------------- Destructor ---------------------------------*/
246 SprocCondVarBase::~SprocCondVarBase(void)
250 /*--------------------------- Construction --------------------------------*/
252 bool SprocCondVarBase::init(void)
254 ThreadManager
*pThreadManager
= ThreadManager::the();
256 if(pThreadManager
== NULL
)
259 if(pThreadManager
->getArena() == NULL
)
262 #ifdef OSG_SPROC_USE_LOCK
263 _pLowLevelLock
= usnewlock(pThreadManager
->getArena());
265 if(_pLowLevelLock
== NULL
)
268 usinitlock(_pLowLevelLock
);
271 _pLowLevelSema
= usnewsema(pThreadManager
->getArena(), 1);
273 if(_pLowLevelSema
== NULL
)
276 usinitsema(_pLowLevelSema
, 1);
277 usctlsema (_pLowLevelSema
, CS_RECURSIVEON
, NULL
);
283 /*--------------------------- Destruction ---------------------------------*/
285 void SprocCondVarBase::shutdown(void)
287 ThreadManager
*pThreadManager
= ThreadManager::the();
289 if(pThreadManager
== NULL
)
292 if(pThreadManager
->getArena() == NULL
)
295 #ifdef OSG_SPROC_USE_LOCK
296 if(_pLowLevelLock
!= NULL
)
298 usfreelock(_pLowLevelLock
, pThreadManager
->getArena());
300 _pLowLevelLock
= NULL
;
303 if(_pLowLevelSema
!= NULL
)
305 usfreesema(_pLowLevelSema
, pThreadManager
->getArena());
307 _pLowLevelSema
= NULL
;
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
328 0x7fffffff, // max count
330 InitializeCriticalSection(&cv
->waiters_count_lock_
);
331 cv
->waiters_done_
= CreateEvent (NULL
, // no security
333 FALSE
, // non-signaled initially
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.
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
);
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
);
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.
390 ReleaseSemaphore(cv
->sema_
, 1, 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;
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
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;
427 LeaveCriticalSection(&cv
->waiters_count_lock_
);
435 //---------------------------------------------------------------------------
437 //---------------------------------------------------------------------------
439 /*--------------------------- Constructors --------------------------------*/
441 WinThreadCondVarBase::WinThreadCondVarBase(void) :
447 WinThreadCondVarBase::WinThreadCondVarBase(const Char8
*szName
,
450 Inherited(szName
, uiId
, bGlobal
),
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
477 sema_
= CreateSemaphore(NULL
, // no security
479 0x7fffffff, // max count
481 InitializeCriticalSection(&waiters_count_lock_
);
482 waiters_done_
= CreateEvent(NULL
, // no security
484 FALSE
, // non-signaled initially
488 OSG_ASSERT(false && "CondVar::init() Not implemented for versions of Windows < 4.0");
493 bool WinThreadCondVarBase::wait(const Int32 timeToWait
)
495 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
496 // Avoid race conditions.
497 EnterCriticalSection (&waiters_count_lock_
);
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...
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.
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
);
529 // Always regain the external mutex since that's the guarantee we
530 // give to our callers.
531 WaitForSingleObject(_pMutex
, INFINITE
);
534 OSG_ASSERT(false && "CondVar::wait() Not implemented for versions of Windows < 4.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.
549 ReleaseSemaphore(sema_
, 1, 0);
552 OSG_ASSERT(false && "CondVar::signal() Not implemented for versions of Windows < 4.0");
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.
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
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.
589 LeaveCriticalSection(&waiters_count_lock_
);
592 OSG_ASSERT(false && "CondVar::broadcast() Not implemented for versions of Windows < 4.0");
596 /*-------------------------- Destruction ----------------------------------*/
598 void WinThreadCondVarBase::shutdown(void)
600 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
603 CloseHandle(_pMutex
);
609 DeleteCriticalSection(&waiters_count_lock_
);
610 if(waiters_done_
!= NULL
)
612 CloseHandle(waiters_done_
);
615 OSG_ASSERT(false && "CondVar::shutdown() Not implemented for versions of Windows < 4.0");
619 #endif /* OSG_USE_WINTHREADS */
623 //---------------------------------------------------------------------------
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)
659 /*--------------------------- Constructors --------------------------------*/
661 CondVar::CondVar(void) :
666 CondVar::CondVar(const Char8
*szName
, UInt32 uiId
, bool bGlobal
) :
667 Inherited(szName
, uiId
, bGlobal
)
671 /*---------------------------- Destructor ---------------------------------*/
673 CondVar::~CondVar(void)
677 ThreadManager::the()->remove(this);