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):
104 PThreadCondVarBase::PThreadCondVarBase(const Char8
*szName
,
115 /*---------------------------- Destructor ---------------------------------*/
117 PThreadCondVarBase::~PThreadCondVarBase(void)
121 /*--------------------------- Construction --------------------------------*/
123 bool PThreadCondVarBase::init(void)
125 pthread_mutexattr_t lockAttr
;
127 pthread_mutexattr_init(&lockAttr
);
129 pthread_mutexattr_settype(&lockAttr
, PTHREAD_MUTEX_RECURSIVE
);
131 pthread_mutex_init(&(_pLowLevelLock
), &lockAttr
);
133 // Initialize the condition variable.
134 pthread_cond_init(&(_pLowLevelCondVar
), NULL
);
139 /*--------------------------- Destruction ---------------------------------*/
141 void PThreadCondVarBase::shutdown(void)
143 pthread_mutex_destroy(&(_pLowLevelLock
));
144 pthread_cond_destroy(&(_pLowLevelCondVar
));
147 bool PThreadCondVarBase::wait(const Int32 timeToWait
)
151 // Wait indefinitely on the condition variable.
154 const int retcode
= pthread_cond_wait(&(_pLowLevelCondVar
), &(_pLowLevelLock
));
156 // If pthread_cond_wait(3) returned non-zero status, then we throw
157 // an exception. Otherwise, we return true.
163 // Wait for no longer than the given timeout period to acquire the lock
164 // on the condition variable.
167 struct timeval now
; // The current time
168 struct timespec abs_timeout
; // The absolute time of the timeout
170 const UInt64
UsecsPerSec(1000000);
172 // Calculate the absolute time for wait timeout
173 gettimeofday(&now
, NULL
);
175 UInt64 abs_secs
= now
.tv_sec
+
176 static_cast<long> (timeToWait
/ 1000);
177 UInt64 abs_usecs
= now
.tv_usec
+
178 static_cast<long>((timeToWait
% 1000) * 1000);
180 if(abs_usecs
> UsecsPerSec
) // Have extra seconds
182 abs_secs
+= abs_usecs
/ UsecsPerSec
; // Get the number of seconds
183 abs_usecs
= abs_usecs
% UsecsPerSec
;
186 abs_timeout
.tv_sec
= abs_secs
;
187 abs_timeout
.tv_nsec
= 1000 * (abs_usecs
);
188 OSG_ASSERT(abs_timeout
.tv_nsec
< Int64(UsecsPerSec
* 1000) &&
189 "Nano seconds out of range (greater then one second).");
191 const int retcode
= pthread_cond_timedwait(&(_pLowLevelCondVar
),
195 // Successful completion: return true.
210 #endif /* OSG_USE_PTHREADS */
213 #if defined (OSG_USE_SPROC)
215 //---------------------------------------------------------------------------
217 //---------------------------------------------------------------------------
219 /*--------------------------- Constructors --------------------------------*/
221 SprocCondVarBase::SprocCondVarBase(void):
223 #ifdef OSG_SPROC_USE_LOCK
231 SprocCondVarBase::SprocCondVarBase(const Char8
*szName
,
233 Inherited (szName
, uiId
),
234 _pLowLevelLock(NULL
)
235 #ifdef OSG_SPROC_USE_LOCK
236 _pLowLevelLock(NULL
)
238 _pLowLevelSema(NULL
)
243 /*---------------------------- Destructor ---------------------------------*/
245 SprocCondVarBase::~SprocCondVarBase(void)
249 /*--------------------------- Construction --------------------------------*/
251 bool SprocCondVarBase::init(void)
253 ThreadManager
*pThreadManager
= ThreadManager::the();
255 if(pThreadManager
== NULL
)
258 if(pThreadManager
->getArena() == NULL
)
261 #ifdef OSG_SPROC_USE_LOCK
262 _pLowLevelLock
= usnewlock(pThreadManager
->getArena());
264 if(_pLowLevelLock
== NULL
)
267 usinitlock(_pLowLevelLock
);
270 _pLowLevelSema
= usnewsema(pThreadManager
->getArena(), 1);
272 if(_pLowLevelSema
== NULL
)
275 usinitsema(_pLowLevelSema
, 1);
276 usctlsema (_pLowLevelSema
, CS_RECURSIVEON
, NULL
);
282 /*--------------------------- Destruction ---------------------------------*/
284 void SprocCondVarBase::shutdown(void)
286 ThreadManager
*pThreadManager
= ThreadManager::the();
288 if(pThreadManager
== NULL
)
291 if(pThreadManager
->getArena() == NULL
)
294 #ifdef OSG_SPROC_USE_LOCK
295 if(_pLowLevelLock
!= NULL
)
297 usfreelock(_pLowLevelLock
, pThreadManager
->getArena());
299 _pLowLevelLock
= NULL
;
302 if(_pLowLevelSema
!= NULL
)
304 usfreesema(_pLowLevelSema
, pThreadManager
->getArena());
306 _pLowLevelSema
= NULL
;
311 /*------------------------------- CondVar ---------------------------------*/
313 #endif /* OSG_USE_SPROC */
317 #if defined (OSG_USE_WINTHREADS)
319 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
321 int pthread_cond_init(pthread_cond_t
*cv
, void *dummy
)
323 cv
->waiters_count_
= 0;
324 cv
->was_broadcast_
= 0;
325 cv
->sema_
= CreateSemaphore(NULL
, // no security
327 0x7fffffff, // max count
329 InitializeCriticalSection(&cv
->waiters_count_lock_
);
330 cv
->waiters_done_
= CreateEvent (NULL
, // no security
332 FALSE
, // non-signaled initially
337 int pthread_cond_wait(pthread_cond_t
*cv
,
338 pthread_mutex_t
*external_mutex
)
340 // Avoid race conditions.
341 EnterCriticalSection(&cv
->waiters_count_lock_
);
342 cv
->waiters_count_
++;
343 LeaveCriticalSection(&cv
->waiters_count_lock_
);
345 // This call atomically releases the mutex and waits on the
346 // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
347 // are called by another thread.
348 ::SignalObjectAndWait(*external_mutex
, cv
->sema_
, INFINITE
, FALSE
);
350 // Reacquire lock to avoid race conditions.
351 EnterCriticalSection(&cv
->waiters_count_lock_
);
353 // We're no longer waiting...
354 cv
->waiters_count_
--;
356 // Check to see if we're the last waiter after <pthread_cond_broadcast>.
357 int last_waiter
= cv
->was_broadcast_
&& cv
->waiters_count_
== 0;
359 LeaveCriticalSection(&cv
->waiters_count_lock_
);
361 // If we're the last waiter thread during this particular broadcast
362 // then let all the other threads proceed.
365 // This call atomically signals the <waiters_done_> event and waits until
366 // it can acquire the <external_mutex>. This is required to ensure fairness.
367 ::SignalObjectAndWait(cv
->waiters_done_
, *external_mutex
, INFINITE
, FALSE
);
371 // Always regain the external mutex since that's the guarantee we
372 // give to our callers.
373 //WaitForSingleObject (*external_mutex);
374 WaitForSingleObject(cv
->waiters_done_
, INFINITE
);
380 int pthread_cond_signal(pthread_cond_t
*cv
)
382 EnterCriticalSection(&cv
->waiters_count_lock_
);
383 int have_waiters
= cv
->waiters_count_
> 0;
384 LeaveCriticalSection(&cv
->waiters_count_lock_
);
386 // If there aren't any waiters, then this is a no-op.
389 ReleaseSemaphore(cv
->sema_
, 1, 0);
394 int pthread_cond_broadcast (pthread_cond_t
*cv
)
396 // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
397 // consistent relative to each other.
398 EnterCriticalSection(&cv
->waiters_count_lock_
);
399 int have_waiters
= 0;
401 if(cv
->waiters_count_
> 0)
403 // We are broadcasting, even if there is just one waiter...
404 // Record that we are broadcasting, which helps optimize
405 // <pthread_cond_wait> for the non-broadcast case.
406 cv
->was_broadcast_
= 1;
412 // Wake up all the waiters atomically.
413 ReleaseSemaphore(cv
->sema_
, cv
->waiters_count_
, 0);
415 LeaveCriticalSection(&cv
->waiters_count_lock_
);
417 // Wait for all the awakened threads to acquire the counting
419 WaitForSingleObject(cv
->waiters_done_
, INFINITE
);
420 // This assignment is okay, even without the <waiters_count_lock_> held
421 // because no other waiter threads can wake up to access it.
422 cv
->was_broadcast_
= 0;
426 LeaveCriticalSection(&cv
->waiters_count_lock_
);
434 //---------------------------------------------------------------------------
436 //---------------------------------------------------------------------------
438 /*--------------------------- Constructors --------------------------------*/
440 WinThreadCondVarBase::WinThreadCondVarBase(void) :
446 WinThreadCondVarBase::WinThreadCondVarBase(const Char8
*szName
,
449 Inherited(szName
, uiId
, bGlobal
),
454 /*---------------------------- Destructor ---------------------------------*/
456 WinThreadCondVarBase::~WinThreadCondVarBase(void)
460 /*-------------------------- Construction ---------------------------------*/
462 bool WinThreadCondVarBase::init(void)
464 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
465 _pMutex
= CreateMutex(NULL
, // no security attributes
466 FALSE
, // initially not owned
467 _szName
); // name of mutex
476 sema_
= CreateSemaphore(NULL
, // no security
478 0x7fffffff, // max count
480 InitializeCriticalSection(&waiters_count_lock_
);
481 waiters_done_
= CreateEvent(NULL
, // no security
483 FALSE
, // non-signaled initially
487 OSG_ASSERT(false && "CondVar::init() Not implemented for versions of Windows < 4.0");
492 bool WinThreadCondVarBase::wait(const Int32 timeToWait
)
494 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
495 // Avoid race conditions.
496 EnterCriticalSection (&waiters_count_lock_
);
498 LeaveCriticalSection (&waiters_count_lock_
);
500 // This call atomically releases the mutex and waits on the
501 // semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
502 // are called by another thread.
503 SignalObjectAndWait(_pMutex
, sema_
, INFINITE
, FALSE
);
505 // Reacquire lock to avoid race conditions.
506 EnterCriticalSection(&waiters_count_lock_
);
508 // We're no longer waiting...
511 // Check to see if we're the last waiter after <pthread_cond_broadcast>.
512 int last_waiter
= was_broadcast_
&& waiters_count_
== 0;
514 LeaveCriticalSection(&waiters_count_lock_
);
516 // XXX: Need to use timeToWait.
518 // If we're the last waiter thread during this particular broadcast
519 // then let all the other threads proceed.
522 // This call atomically signals the <waiters_done_> event and waits until
523 // it can acquire the <external_mutex>. This is required to ensure fairness.
524 SignalObjectAndWait(waiters_done_
, _pMutex
, INFINITE
, FALSE
);
528 // Always regain the external mutex since that's the guarantee we
529 // give to our callers.
530 WaitForSingleObject(_pMutex
, INFINITE
);
533 OSG_ASSERT(false && "CondVar::wait() Not implemented for versions of Windows < 4.0");
538 void WinThreadCondVarBase::signal()
540 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
541 EnterCriticalSection(&waiters_count_lock_
);
542 int have_waiters
= waiters_count_
> 0;
543 LeaveCriticalSection(&waiters_count_lock_
);
545 // If there aren't any waiters, then this is a no-op.
548 ReleaseSemaphore(sema_
, 1, 0);
551 OSG_ASSERT(false && "CondVar::signal() Not implemented for versions of Windows < 4.0");
555 void WinThreadCondVarBase::broadcast()
557 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
558 // This is needed to ensure that <waiters_count_> and <was_broadcast_> are
559 // consistent relative to each other.
560 EnterCriticalSection(&waiters_count_lock_
);
561 int have_waiters
= 0;
563 if(waiters_count_
> 0)
565 // We are broadcasting, even if there is just one waiter...
566 // Record that we are broadcasting, which helps optimize
567 // <pthread_cond_wait> for the non-broadcast case.
574 // Wake up all the waiters atomically.
575 ReleaseSemaphore(sema_
, waiters_count_
, 0);
577 LeaveCriticalSection(&waiters_count_lock_
);
579 // Wait for all the awakened threads to acquire the counting
581 WaitForSingleObject(waiters_done_
, INFINITE
);
582 // This assignment is okay, even without the <waiters_count_lock_> held
583 // because no other waiter threads can wake up to access it.
588 LeaveCriticalSection(&waiters_count_lock_
);
591 OSG_ASSERT(false && "CondVar::broadcast() Not implemented for versions of Windows < 4.0");
595 /*-------------------------- Destruction ----------------------------------*/
597 void WinThreadCondVarBase::shutdown(void)
599 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
602 CloseHandle(_pMutex
);
608 DeleteCriticalSection(&waiters_count_lock_
);
609 if(waiters_done_
!= NULL
)
611 CloseHandle(waiters_done_
);
614 OSG_ASSERT(false && "CondVar::shutdown() Not implemented for versions of Windows < 4.0");
618 #endif /* OSG_USE_WINTHREADS */
622 //---------------------------------------------------------------------------
624 //---------------------------------------------------------------------------
626 MPCondVarType
CondVar::_type("OSGCondVar", "OSGMPBase", &CondVar::create
);
628 /*------------------------------- Get -------------------------------------*/
630 CondVar::ObjTransitPtr
CondVar::get(const Char8
*szName
, bool bGlobal
)
632 return ThreadManager::the()->getCondVar(szName
, bGlobal
, "OSGCondVar");
635 CondVar
*CondVar::find(const Char8
*szName
)
637 return ThreadManager::the()->findCondVar(szName
);
641 /*------------------------------ Create -----------------------------------*/
643 CondVar
*CondVar::create(const Char8
*szName
, UInt32 uiId
, bool bGlobal
)
645 CondVar
*returnValue
= NULL
;
647 returnValue
= new CondVar(szName
, uiId
, bGlobal
);
649 if(returnValue
->init() == false)
658 /*--------------------------- Constructors --------------------------------*/
660 CondVar::CondVar(void) :
665 CondVar::CondVar(const Char8
*szName
, UInt32 uiId
, bool bGlobal
) :
666 Inherited(szName
, uiId
, bGlobal
)
670 /*---------------------------- Destructor ---------------------------------*/
672 CondVar::~CondVar(void)
676 ThreadManager::the()->remove(this);