changed: auto add updateData callback to stages so that stagedata can be updated...
[opensg.git] / Source / Base / Threading / OSGCondVar.cpp
blobed9b341dfc3fec609f25d8078989a9de660d8253
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 _pLowLevelCondVar()
104 PThreadCondVarBase::PThreadCondVarBase(const Char8 *szName,
105 UInt32 uiId,
106 bool bGlobal) :
107 Inherited (szName,
108 uiId,
109 bGlobal),
110 _pLowLevelLock ( ),
111 _pLowLevelCondVar( )
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);
136 return true;
139 /*--------------------------- Destruction ---------------------------------*/
141 void PThreadCondVarBase::shutdown(void)
143 pthread_mutex_destroy(&(_pLowLevelLock));
144 pthread_cond_destroy(&(_pLowLevelCondVar));
147 bool PThreadCondVarBase::wait(const Int32 timeToWait)
149 bool result(true);
151 // Wait indefinitely on the condition variable.
152 if(timeToWait < 0)
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.
158 if(retcode != 0)
160 return false;
163 // Wait for no longer than the given timeout period to acquire the lock
164 // on the condition variable.
165 else
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),
192 &(_pLowLevelLock),
193 &abs_timeout);
195 // Successful completion: return true.
196 if( 0 == retcode )
198 result = true;
200 else
202 result = false;
206 return result;
210 #endif /* OSG_USE_PTHREADS */
213 #if defined (OSG_USE_SPROC)
215 //---------------------------------------------------------------------------
216 // Class
217 //---------------------------------------------------------------------------
219 /*--------------------------- Constructors --------------------------------*/
221 SprocCondVarBase::SprocCondVarBase(void):
222 Inherited ( ),
223 #ifdef OSG_SPROC_USE_LOCK
224 _pLowLevelLock(NULL)
225 #else
226 _pLowLevelSema(NULL)
227 #endif
231 SprocCondVarBase::SprocCondVarBase(const Char8 *szName,
232 UInt32 uiId ):
233 Inherited (szName, uiId),
234 _pLowLevelLock(NULL )
235 #ifdef OSG_SPROC_USE_LOCK
236 _pLowLevelLock(NULL )
237 #else
238 _pLowLevelSema(NULL )
239 #endif
243 /*---------------------------- Destructor ---------------------------------*/
245 SprocCondVarBase::~SprocCondVarBase(void)
249 /*--------------------------- Construction --------------------------------*/
251 bool SprocCondVarBase::init(void)
253 ThreadManager *pThreadManager = ThreadManager::the();
255 if(pThreadManager == NULL)
256 return false;
258 if(pThreadManager->getArena() == NULL)
259 return false;
261 #ifdef OSG_SPROC_USE_LOCK
262 _pLowLevelLock = usnewlock(pThreadManager->getArena());
264 if(_pLowLevelLock == NULL)
265 return false;
267 usinitlock(_pLowLevelLock);
269 #else
270 _pLowLevelSema = usnewsema(pThreadManager->getArena(), 1);
272 if(_pLowLevelSema == NULL)
273 return false;
275 usinitsema(_pLowLevelSema, 1);
276 usctlsema (_pLowLevelSema, CS_RECURSIVEON, NULL);
277 #endif
279 return true;
282 /*--------------------------- Destruction ---------------------------------*/
284 void SprocCondVarBase::shutdown(void)
286 ThreadManager *pThreadManager = ThreadManager::the();
288 if(pThreadManager == NULL)
289 return;
291 if(pThreadManager->getArena() == NULL)
292 return;
294 #ifdef OSG_SPROC_USE_LOCK
295 if(_pLowLevelLock != NULL)
297 usfreelock(_pLowLevelLock, pThreadManager->getArena());
299 _pLowLevelLock = NULL;
301 #else
302 if(_pLowLevelSema != NULL)
304 usfreesema(_pLowLevelSema, pThreadManager->getArena());
306 _pLowLevelSema = NULL;
308 #endif
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
326 0, // initially 0
327 0x7fffffff, // max count
328 NULL); // unnamed
329 InitializeCriticalSection(&cv->waiters_count_lock_);
330 cv->waiters_done_ = CreateEvent (NULL, // no security
331 FALSE, // auto-reset
332 FALSE, // non-signaled initially
333 NULL); // unnamed
334 return 0;
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.
363 if(last_waiter)
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);
369 else
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);
377 return 0;
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.
387 if(have_waiters)
389 ReleaseSemaphore(cv->sema_, 1, 0);
391 return 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;
407 have_waiters = 1;
410 if(have_waiters)
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
418 // semaphore.
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;
424 else
426 LeaveCriticalSection(&cv->waiters_count_lock_);
429 return 0;
432 #endif
434 //---------------------------------------------------------------------------
435 // Class
436 //---------------------------------------------------------------------------
438 /*--------------------------- Constructors --------------------------------*/
440 WinThreadCondVarBase::WinThreadCondVarBase(void) :
441 Inherited( )
442 , _pMutex (NULL)
446 WinThreadCondVarBase::WinThreadCondVarBase(const Char8 *szName,
447 UInt32 uiId,
448 bool bGlobal) :
449 Inherited(szName, uiId, bGlobal),
450 _pMutex (NULL )
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
469 if(_pMutex == NULL)
471 return false;
474 waiters_count_ = 0;
475 was_broadcast_ = 0;
476 sema_ = CreateSemaphore(NULL, // no security
477 0, // initially 0
478 0x7fffffff, // max count
479 NULL); // unnamed
480 InitializeCriticalSection(&waiters_count_lock_);
481 waiters_done_ = CreateEvent(NULL, // no security
482 FALSE, // auto-reset
483 FALSE, // non-signaled initially
484 NULL); // unnamed
485 return true;
486 #else
487 OSG_ASSERT(false && "CondVar::init() Not implemented for versions of Windows < 4.0");
488 return false;
489 #endif
492 bool WinThreadCondVarBase::wait(const Int32 timeToWait)
494 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
495 // Avoid race conditions.
496 EnterCriticalSection (&waiters_count_lock_);
497 waiters_count_++;
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...
509 waiters_count_--;
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.
520 if(last_waiter)
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);
526 else
528 // Always regain the external mutex since that's the guarantee we
529 // give to our callers.
530 WaitForSingleObject(_pMutex, INFINITE);
532 #else
533 OSG_ASSERT(false && "CondVar::wait() Not implemented for versions of Windows < 4.0");
534 #endif
535 return 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.
546 if(have_waiters)
548 ReleaseSemaphore(sema_, 1, 0);
550 #else
551 OSG_ASSERT(false && "CondVar::signal() Not implemented for versions of Windows < 4.0");
552 #endif
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.
568 was_broadcast_ = 1;
569 have_waiters = 1;
572 if(have_waiters)
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
580 // semaphore.
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.
584 was_broadcast_ = 0;
586 else
588 LeaveCriticalSection(&waiters_count_lock_);
590 #else
591 OSG_ASSERT(false && "CondVar::broadcast() Not implemented for versions of Windows < 4.0");
592 #endif
595 /*-------------------------- Destruction ----------------------------------*/
597 void WinThreadCondVarBase::shutdown(void)
599 #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x0400
600 if(_pMutex != NULL)
602 CloseHandle(_pMutex);
604 if(sema_ != NULL)
606 CloseHandle(sema_);
608 DeleteCriticalSection(&waiters_count_lock_);
609 if(waiters_done_ != NULL)
611 CloseHandle(waiters_done_);
613 #else
614 OSG_ASSERT(false && "CondVar::shutdown() Not implemented for versions of Windows < 4.0");
615 #endif
618 #endif /* OSG_USE_WINTHREADS */
622 //---------------------------------------------------------------------------
623 // Class
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)
651 delete returnValue;
652 returnValue = NULL;
655 return returnValue;
658 /*--------------------------- Constructors --------------------------------*/
660 CondVar::CondVar(void) :
661 Inherited()
665 CondVar::CondVar(const Char8 *szName, UInt32 uiId, bool bGlobal) :
666 Inherited(szName, uiId, bGlobal)
670 /*---------------------------- Destructor ---------------------------------*/
672 CondVar::~CondVar(void)
674 _bGlobal = false;
676 ThreadManager::the()->remove(this);
678 shutdown();