Files
OpenSceneGraph/src/OpenThreads/win32/Win32ConditionPrivateData.h
Robert Osfield d703c58936 From Blasius Czink, "Among other things I added support for atomic operations on BSD-like systems and additional methods (for "and", "or", "xor").
"

and a later post the same osg-submissions thread:

"it's been a while since I have made the changes but I think it was due to problems with static builds of OpenThreads on windows. I was using
OpenThreads in a communication/synchronisation library (without
OpenSceneGraph). It seems I forgot to post a small change in the CMakeLists file of OpenThreads. If a user turns DYNAMIC_OPENTHREADS to OFF (static build) OT_LIBRARY_STATIC will be defined in the Config.
Without these changes a windows user will always end up with a "__declspec(dllexport)" or "__declspec(dllimport)" which is a problem for static builds."

And another post from Blasius on this topic:

"I tested with VS2005 and VS2008. For 32 bit everything works as expected. For x64 and VS2008 I could successfully do the cmake-configure and then the compilation but I had occasional crashes of cmTryCompileExec.exe (during the cmake-configure phase) which seems to be a cmake bug. With VS2005 and 64bit cmake does not set _OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED although the interlocked functionality should be there. If I place the source snippet from the CHECK_CXX_SOURCE_RUNS macro to a separate sourcefile I can compile and run the resulting executable successfully. Forcing OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED (on VS2005/x64) reveals a bug in "intrin.h" which seems to be fixed in VS2008 but not in VS2005.

In case anyone is interested the lines:
__MACHINEI(unsigned char _interlockedbittestandset(long *a, long b))
__MACHINEI(unsigned char _interlockedbittestandreset(long *a, long b))
__MACHINEX64(unsigned char _interlockedbittestandset64(__int64 *a, __int64 b))
__MACHINEX64(unsigned char _interlockedbittestandreset64(__int64 *a, __int64 b))

should be changed to:
__MACHINEI(unsigned char _interlockedbittestandset(long volatile *a, long b))
__MACHINEI(unsigned char _interlockedbittestandreset(long volatile *a, long b))
__MACHINEX64(unsigned char _interlockedbittestandset64(__int64 volatile *a, __int64 b))
__MACHINEX64(unsigned char _interlockedbittestandreset64(__int64 volatile *a, __int64 b))

The worst thing that can happen is that interlocked funtionality is not detected during cmake-configure and the mutex fallback is used.
Which reminds me another small glitch in the Atomic header so I attached a corrected version.



    Why is the OT_LIBRARY_STATIC added to the config file? It is not needed anywhere.

OT_LIBRARY_STATIC is needed if you are doing static-builds on Windows. See my previous post on that.
"
2008-10-27 10:42:58 +00:00

166 lines
4.0 KiB
C++

/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
//
//
// WIN32ConditionPrivateData.h - Private data structure for Condition
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#ifndef _WIN32CONDITIONPRIVATEDATA_H_
#define _WIN32CONDITIONPRIVATEDATA_H_
#ifndef _WINDOWS_
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0400
#include <windows.h>
#endif
#include <OpenThreads/ScopedLock>
#include "Win32ThreadPrivateData.h"
#include "HandleHolder.h"
#define InterlockedGet(x) InterlockedExchangeAdd(x,0)
namespace OpenThreads {
class Condition;
class Win32ConditionPrivateData {
public:
friend class Condition;
/// number of waiters.
long waiters_;
Win32ConditionPrivateData ()
:waiters_(0),
was_broadcast_(0),
sema_(CreateSemaphore(NULL,0,0x7fffffff,NULL)),
waiters_done_(CreateEvent(NULL,FALSE,FALSE,NULL))
{
}
~Win32ConditionPrivateData ();
inline int broadcast ()
{
int have_waiters = 0;
long w = InterlockedGet(&waiters_);
if (w > 0)
{
// we are broadcasting.
was_broadcast_ = 1;
have_waiters = 1;
}
int result = 0;
if (have_waiters)
{
// Wake up all the waiters.
ReleaseSemaphore(sema_.get(),waiters_,NULL);
cooperativeWait(waiters_done_.get(), INFINITE);
//end of broadcasting
was_broadcast_ = 0;
}
return result;
}
inline int signal()
{
long w = InterlockedGet(&waiters_);
int have_waiters = w > 0;
int result = 0;
if (have_waiters)
{
if( !ReleaseSemaphore(sema_.get(),1,NULL) )
result = -1;
}
return result;
}
inline int wait (Mutex& external_mutex, long timeout_ms)
{
// Prevent race conditions on the <waiters_> count.
InterlockedIncrement(&waiters_);
int result = 0;
ReverseScopedLock<Mutex> lock(external_mutex);
// wait in timeslices, giving testCancel() a change to
// exit the thread if requested.
try {
DWORD dwResult = cooperativeWait(sema_.get(), timeout_ms);
if(dwResult != WAIT_OBJECT_0)
result = (int)dwResult;
}
catch(...){
// thread is canceled in cooperative wait , do cleanup
InterlockedDecrement(&waiters_);
long w = InterlockedGet(&waiters_);
int last_waiter = was_broadcast_ && w == 0;
if (last_waiter) SetEvent(waiters_done_.get());
// rethrow
throw;
}
// We're ready to return, so there's one less waiter.
InterlockedDecrement(&waiters_);
long w = InterlockedGet(&waiters_);
int last_waiter = was_broadcast_ && w == 0;
if (result != -1 && last_waiter)
SetEvent(waiters_done_.get());
return result;
}
protected:
/// Serialize access to the waiters count.
/// Mutex waiters_lock_;
/// Queue up threads waiting for the condition to become signaled.
HandleHolder sema_;
/**
* An auto reset event used by the broadcast/signal thread to wait
* for the waiting thread(s) to wake up and get a chance at the
* semaphore.
*/
HandleHolder waiters_done_;
/// Keeps track of whether we were broadcasting or just signaling.
size_t was_broadcast_;
};
#undef InterlockedGet
}
#endif // !_WIN32CONDITIONPRIVATEDATA_H_