summaryrefslogtreecommitdiff
path: root/thirdparty/bullet/src/LinearMath/btThreads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/bullet/src/LinearMath/btThreads.cpp')
-rw-r--r--thirdparty/bullet/src/LinearMath/btThreads.cpp722
1 files changed, 0 insertions, 722 deletions
diff --git a/thirdparty/bullet/src/LinearMath/btThreads.cpp b/thirdparty/bullet/src/LinearMath/btThreads.cpp
deleted file mode 100644
index 59a7ea36e9..0000000000
--- a/thirdparty/bullet/src/LinearMath/btThreads.cpp
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
-Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com
-
-This software is provided 'as-is', without any express or implied warranty.
-In no event will the authors be held liable for any damages arising from the use of this software.
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it freely,
-subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
-*/
-
-
-#include "btThreads.h"
-#include "btQuickprof.h"
-#include <algorithm> // for min and max
-
-
-#if BT_USE_OPENMP && BT_THREADSAFE
-
-#include <omp.h>
-
-#endif // #if BT_USE_OPENMP && BT_THREADSAFE
-
-
-#if BT_USE_PPL && BT_THREADSAFE
-
-// use Microsoft Parallel Patterns Library (installed with Visual Studio 2010 and later)
-#include <ppl.h> // if you get a compile error here, check whether your version of Visual Studio includes PPL
-// Visual Studio 2010 and later should come with it
-#include <concrtrm.h> // for GetProcessorCount()
-
-#endif // #if BT_USE_PPL && BT_THREADSAFE
-
-
-#if BT_USE_TBB && BT_THREADSAFE
-
-// use Intel Threading Building Blocks for thread management
-#define __TBB_NO_IMPLICIT_LINKAGE 1
-#include <tbb/tbb.h>
-#include <tbb/task_scheduler_init.h>
-#include <tbb/parallel_for.h>
-#include <tbb/blocked_range.h>
-
-#endif // #if BT_USE_TBB && BT_THREADSAFE
-
-
-#if BT_THREADSAFE
-//
-// Lightweight spin-mutex based on atomics
-// Using ordinary system-provided mutexes like Windows critical sections was noticeably slower
-// presumably because when it fails to lock at first it would sleep the thread and trigger costly
-// context switching.
-//
-
-#if __cplusplus >= 201103L
-
-// for anything claiming full C++11 compliance, use C++11 atomics
-// on GCC or Clang you need to compile with -std=c++11
-#define USE_CPP11_ATOMICS 1
-
-#elif defined( _MSC_VER )
-
-// on MSVC, use intrinsics instead
-#define USE_MSVC_INTRINSICS 1
-
-#elif defined( __GNUC__ ) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
-
-// available since GCC 4.7 and some versions of clang
-// todo: check for clang
-#define USE_GCC_BUILTIN_ATOMICS 1
-
-#elif defined( __GNUC__ ) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
-
-// available since GCC 4.1
-#define USE_GCC_BUILTIN_ATOMICS_OLD 1
-
-#endif
-
-
-#if USE_CPP11_ATOMICS
-
-#include <atomic>
-#include <thread>
-
-#define THREAD_LOCAL_STATIC thread_local static
-
-bool btSpinMutex::tryLock()
-{
- std::atomic<int>* aDest = reinterpret_cast<std::atomic<int>*>(&mLock);
- int expected = 0;
- return std::atomic_compare_exchange_weak_explicit( aDest, &expected, int(1), std::memory_order_acq_rel, std::memory_order_acquire );
-}
-
-void btSpinMutex::lock()
-{
- // note: this lock does not sleep the thread.
- while (! tryLock())
- {
- // spin
- }
-}
-
-void btSpinMutex::unlock()
-{
- std::atomic<int>* aDest = reinterpret_cast<std::atomic<int>*>(&mLock);
- std::atomic_store_explicit( aDest, int(0), std::memory_order_release );
-}
-
-
-#elif USE_MSVC_INTRINSICS
-
-#define WIN32_LEAN_AND_MEAN
-
-#include <windows.h>
-#include <intrin.h>
-
-#define THREAD_LOCAL_STATIC __declspec( thread ) static
-
-
-bool btSpinMutex::tryLock()
-{
- volatile long* aDest = reinterpret_cast<long*>(&mLock);
- return ( 0 == _InterlockedCompareExchange( aDest, 1, 0) );
-}
-
-void btSpinMutex::lock()
-{
- // note: this lock does not sleep the thread
- while (! tryLock())
- {
- // spin
- }
-}
-
-void btSpinMutex::unlock()
-{
- volatile long* aDest = reinterpret_cast<long*>( &mLock );
- _InterlockedExchange( aDest, 0 );
-}
-
-#elif USE_GCC_BUILTIN_ATOMICS
-
-#define THREAD_LOCAL_STATIC static __thread
-
-
-bool btSpinMutex::tryLock()
-{
- int expected = 0;
- bool weak = false;
- const int memOrderSuccess = __ATOMIC_ACQ_REL;
- const int memOrderFail = __ATOMIC_ACQUIRE;
- return __atomic_compare_exchange_n(&mLock, &expected, int(1), weak, memOrderSuccess, memOrderFail);
-}
-
-void btSpinMutex::lock()
-{
- // note: this lock does not sleep the thread
- while (! tryLock())
- {
- // spin
- }
-}
-
-void btSpinMutex::unlock()
-{
- __atomic_store_n(&mLock, int(0), __ATOMIC_RELEASE);
-}
-
-#elif USE_GCC_BUILTIN_ATOMICS_OLD
-
-
-#define THREAD_LOCAL_STATIC static __thread
-
-bool btSpinMutex::tryLock()
-{
- return __sync_bool_compare_and_swap(&mLock, int(0), int(1));
-}
-
-void btSpinMutex::lock()
-{
- // note: this lock does not sleep the thread
- while (! tryLock())
- {
- // spin
- }
-}
-
-void btSpinMutex::unlock()
-{
- // write 0
- __sync_fetch_and_and(&mLock, int(0));
-}
-
-#else //#elif USE_MSVC_INTRINSICS
-
-#error "no threading primitives defined -- unknown platform"
-
-#endif //#else //#elif USE_MSVC_INTRINSICS
-
-#else //#if BT_THREADSAFE
-
-// These should not be called ever
-void btSpinMutex::lock()
-{
- btAssert( !"unimplemented btSpinMutex::lock() called" );
-}
-
-void btSpinMutex::unlock()
-{
- btAssert( !"unimplemented btSpinMutex::unlock() called" );
-}
-
-bool btSpinMutex::tryLock()
-{
- btAssert( !"unimplemented btSpinMutex::tryLock() called" );
- return true;
-}
-
-#define THREAD_LOCAL_STATIC static
-
-#endif // #else //#if BT_THREADSAFE
-
-
-struct ThreadsafeCounter
-{
- unsigned int mCounter;
- btSpinMutex mMutex;
-
- ThreadsafeCounter()
- {
- mCounter = 0;
- --mCounter; // first count should come back 0
- }
-
- unsigned int getNext()
- {
- // no need to optimize this with atomics, it is only called ONCE per thread!
- mMutex.lock();
- mCounter++;
- if ( mCounter >= BT_MAX_THREAD_COUNT )
- {
- btAssert( !"thread counter exceeded" );
- // wrap back to the first worker index
- mCounter = 1;
- }
- unsigned int val = mCounter;
- mMutex.unlock();
- return val;
- }
-};
-
-
-static btITaskScheduler* gBtTaskScheduler;
-static int gThreadsRunningCounter = 0; // useful for detecting if we are trying to do nested parallel-for calls
-static btSpinMutex gThreadsRunningCounterMutex;
-static ThreadsafeCounter gThreadCounter;
-
-
-//
-// BT_DETECT_BAD_THREAD_INDEX tries to detect when there are multiple threads assigned the same thread index.
-//
-// BT_DETECT_BAD_THREAD_INDEX is a developer option to test if
-// certain assumptions about how the task scheduler manages its threads
-// holds true.
-// The main assumption is:
-// - when the threadpool is resized, the task scheduler either
-// 1. destroys all worker threads and creates all new ones in the correct number, OR
-// 2. never destroys a worker thread
-//
-// We make that assumption because we can't easily enumerate the worker threads of a task scheduler
-// to assign nice sequential thread-indexes. We also do not get notified if a worker thread is destroyed,
-// so we can't tell when a thread-index is no longer being used.
-// We allocate thread-indexes as needed with a sequential global thread counter.
-//
-// Our simple thread-counting scheme falls apart if the task scheduler destroys some threads but
-// continues to re-use other threads and the application repeatedly resizes the thread pool of the
-// task scheduler.
-// In order to prevent the thread-counter from exceeding the global max (BT_MAX_THREAD_COUNT), we
-// wrap the thread counter back to 1. This should only happen if the worker threads have all been
-// destroyed and re-created.
-//
-// BT_DETECT_BAD_THREAD_INDEX only works for Win32 right now,
-// but could be adapted to work with pthreads
-#define BT_DETECT_BAD_THREAD_INDEX 0
-
-#if BT_DETECT_BAD_THREAD_INDEX
-
-typedef DWORD ThreadId_t;
-const static ThreadId_t kInvalidThreadId = 0;
-ThreadId_t gDebugThreadIds[ BT_MAX_THREAD_COUNT ];
-
-static ThreadId_t getDebugThreadId()
-{
- return GetCurrentThreadId();
-}
-
-#endif // #if BT_DETECT_BAD_THREAD_INDEX
-
-
-// return a unique index per thread, main thread is 0, worker threads are in [1, BT_MAX_THREAD_COUNT)
-unsigned int btGetCurrentThreadIndex()
-{
- const unsigned int kNullIndex = ~0U;
- THREAD_LOCAL_STATIC unsigned int sThreadIndex = kNullIndex;
- if ( sThreadIndex == kNullIndex )
- {
- sThreadIndex = gThreadCounter.getNext();
- btAssert( sThreadIndex < BT_MAX_THREAD_COUNT );
- }
-#if BT_DETECT_BAD_THREAD_INDEX
- if ( gBtTaskScheduler && sThreadIndex > 0 )
- {
- ThreadId_t tid = getDebugThreadId();
- // if not set
- if ( gDebugThreadIds[ sThreadIndex ] == kInvalidThreadId )
- {
- // set it
- gDebugThreadIds[ sThreadIndex ] = tid;
- }
- else
- {
- if ( gDebugThreadIds[ sThreadIndex ] != tid )
- {
- // this could indicate the task scheduler is breaking our assumptions about
- // how threads are managed when threadpool is resized
- btAssert( !"there are 2 or more threads with the same thread-index!" );
- __debugbreak();
- }
- }
- }
-#endif // #if BT_DETECT_BAD_THREAD_INDEX
- return sThreadIndex;
-}
-
-bool btIsMainThread()
-{
- return btGetCurrentThreadIndex() == 0;
-}
-
-void btResetThreadIndexCounter()
-{
- // for when all current worker threads are destroyed
- btAssert( btIsMainThread() );
- gThreadCounter.mCounter = 0;
-}
-
-btITaskScheduler::btITaskScheduler( const char* name )
-{
- m_name = name;
- m_savedThreadCounter = 0;
- m_isActive = false;
-}
-
-void btITaskScheduler::activate()
-{
- // gThreadCounter is used to assign a thread-index to each worker thread in a task scheduler.
- // The main thread is always thread-index 0, and worker threads are numbered from 1 to 63 (BT_MAX_THREAD_COUNT-1)
- // The thread-indexes need to be unique amongst the threads that can be running simultaneously.
- // Since only one task scheduler can be used at a time, it is OK for a pair of threads that belong to different
- // task schedulers to share the same thread index because they can't be running at the same time.
- // So each task scheduler needs to keep its own thread counter value
- if ( !m_isActive )
- {
- gThreadCounter.mCounter = m_savedThreadCounter; // restore saved thread counter
- m_isActive = true;
- }
-}
-
-void btITaskScheduler::deactivate()
-{
- if ( m_isActive )
- {
- m_savedThreadCounter = gThreadCounter.mCounter; // save thread counter
- m_isActive = false;
- }
-}
-
-void btPushThreadsAreRunning()
-{
- gThreadsRunningCounterMutex.lock();
- gThreadsRunningCounter++;
- gThreadsRunningCounterMutex.unlock();
-}
-
-void btPopThreadsAreRunning()
-{
- gThreadsRunningCounterMutex.lock();
- gThreadsRunningCounter--;
- gThreadsRunningCounterMutex.unlock();
-}
-
-bool btThreadsAreRunning()
-{
- return gThreadsRunningCounter != 0;
-}
-
-
-void btSetTaskScheduler( btITaskScheduler* ts )
-{
- int threadId = btGetCurrentThreadIndex(); // make sure we call this on main thread at least once before any workers run
- if ( threadId != 0 )
- {
- btAssert( !"btSetTaskScheduler must be called from the main thread!" );
- return;
- }
- if ( gBtTaskScheduler )
- {
- // deactivate old task scheduler
- gBtTaskScheduler->deactivate();
- }
- gBtTaskScheduler = ts;
- if ( ts )
- {
- // activate new task scheduler
- ts->activate();
- }
-}
-
-
-btITaskScheduler* btGetTaskScheduler()
-{
- return gBtTaskScheduler;
-}
-
-
-void btParallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body )
-{
-#if BT_THREADSAFE
-
-#if BT_DETECT_BAD_THREAD_INDEX
- if ( !btThreadsAreRunning() )
- {
- // clear out thread ids
- for ( int i = 0; i < BT_MAX_THREAD_COUNT; ++i )
- {
- gDebugThreadIds[ i ] = kInvalidThreadId;
- }
- }
-#endif // #if BT_DETECT_BAD_THREAD_INDEX
-
- btAssert( gBtTaskScheduler != NULL ); // call btSetTaskScheduler() with a valid task scheduler first!
- gBtTaskScheduler->parallelFor( iBegin, iEnd, grainSize, body );
-
-#else // #if BT_THREADSAFE
-
- // non-parallel version of btParallelFor
- btAssert( !"called btParallelFor in non-threadsafe build. enable BT_THREADSAFE" );
- body.forLoop( iBegin, iEnd );
-
-#endif// #if BT_THREADSAFE
-}
-
-
-///
-/// btTaskSchedulerSequential -- non-threaded implementation of task scheduler
-/// (really just useful for testing performance of single threaded vs multi)
-///
-class btTaskSchedulerSequential : public btITaskScheduler
-{
-public:
- btTaskSchedulerSequential() : btITaskScheduler( "Sequential" ) {}
- virtual int getMaxNumThreads() const BT_OVERRIDE { return 1; }
- virtual int getNumThreads() const BT_OVERRIDE { return 1; }
- virtual void setNumThreads( int numThreads ) BT_OVERRIDE {}
- virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
- {
- BT_PROFILE( "parallelFor_sequential" );
- body.forLoop( iBegin, iEnd );
- }
-};
-
-
-#if BT_USE_OPENMP && BT_THREADSAFE
-///
-/// btTaskSchedulerOpenMP -- wrapper around OpenMP task scheduler
-///
-class btTaskSchedulerOpenMP : public btITaskScheduler
-{
- int m_numThreads;
-public:
- btTaskSchedulerOpenMP() : btITaskScheduler( "OpenMP" )
- {
- m_numThreads = 0;
- }
- virtual int getMaxNumThreads() const BT_OVERRIDE
- {
- return omp_get_max_threads();
- }
- virtual int getNumThreads() const BT_OVERRIDE
- {
- return m_numThreads;
- }
- virtual void setNumThreads( int numThreads ) BT_OVERRIDE
- {
- // With OpenMP, because it is a standard with various implementations, we can't
- // know for sure if every implementation has the same behavior of destroying all
- // previous threads when resizing the threadpool
- m_numThreads = ( std::max )( 1, ( std::min )( int( BT_MAX_THREAD_COUNT ), numThreads ) );
- omp_set_num_threads( 1 ); // hopefully, all previous threads get destroyed here
- omp_set_num_threads( m_numThreads );
- m_savedThreadCounter = 0;
- if ( m_isActive )
- {
- btResetThreadIndexCounter();
- }
- }
- virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
- {
- BT_PROFILE( "parallelFor_OpenMP" );
- btPushThreadsAreRunning();
-#pragma omp parallel for schedule( static, 1 )
- for ( int i = iBegin; i < iEnd; i += grainSize )
- {
- BT_PROFILE( "OpenMP_job" );
- body.forLoop( i, ( std::min )( i + grainSize, iEnd ) );
- }
- btPopThreadsAreRunning();
- }
-};
-#endif // #if BT_USE_OPENMP && BT_THREADSAFE
-
-
-#if BT_USE_TBB && BT_THREADSAFE
-///
-/// btTaskSchedulerTBB -- wrapper around Intel Threaded Building Blocks task scheduler
-///
-class btTaskSchedulerTBB : public btITaskScheduler
-{
- int m_numThreads;
- tbb::task_scheduler_init* m_tbbSchedulerInit;
-
-public:
- btTaskSchedulerTBB() : btITaskScheduler( "IntelTBB" )
- {
- m_numThreads = 0;
- m_tbbSchedulerInit = NULL;
- }
- ~btTaskSchedulerTBB()
- {
- if ( m_tbbSchedulerInit )
- {
- delete m_tbbSchedulerInit;
- m_tbbSchedulerInit = NULL;
- }
- }
-
- virtual int getMaxNumThreads() const BT_OVERRIDE
- {
- return tbb::task_scheduler_init::default_num_threads();
- }
- virtual int getNumThreads() const BT_OVERRIDE
- {
- return m_numThreads;
- }
- virtual void setNumThreads( int numThreads ) BT_OVERRIDE
- {
- m_numThreads = ( std::max )( 1, ( std::min )( int(BT_MAX_THREAD_COUNT), numThreads ) );
- if ( m_tbbSchedulerInit )
- {
- // destroys all previous threads
- delete m_tbbSchedulerInit;
- m_tbbSchedulerInit = NULL;
- }
- m_tbbSchedulerInit = new tbb::task_scheduler_init( m_numThreads );
- m_savedThreadCounter = 0;
- if ( m_isActive )
- {
- btResetThreadIndexCounter();
- }
- }
- struct BodyAdapter
- {
- const btIParallelForBody* mBody;
-
- void operator()( const tbb::blocked_range<int>& range ) const
- {
- BT_PROFILE( "TBB_job" );
- mBody->forLoop( range.begin(), range.end() );
- }
- };
- virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
- {
- BT_PROFILE( "parallelFor_TBB" );
- // TBB dispatch
- BodyAdapter tbbBody;
- tbbBody.mBody = &body;
- btPushThreadsAreRunning();
- tbb::parallel_for( tbb::blocked_range<int>( iBegin, iEnd, grainSize ),
- tbbBody,
- tbb::simple_partitioner()
- );
- btPopThreadsAreRunning();
- }
-};
-#endif // #if BT_USE_TBB && BT_THREADSAFE
-
-
-#if BT_USE_PPL && BT_THREADSAFE
-///
-/// btTaskSchedulerPPL -- wrapper around Microsoft Parallel Patterns Lib task scheduler
-///
-class btTaskSchedulerPPL : public btITaskScheduler
-{
- int m_numThreads;
-public:
- btTaskSchedulerPPL() : btITaskScheduler( "PPL" )
- {
- m_numThreads = 0;
- }
- virtual int getMaxNumThreads() const BT_OVERRIDE
- {
- return concurrency::GetProcessorCount();
- }
- virtual int getNumThreads() const BT_OVERRIDE
- {
- return m_numThreads;
- }
- virtual void setNumThreads( int numThreads ) BT_OVERRIDE
- {
- // capping the thread count for PPL due to a thread-index issue
- const int maxThreadCount = (std::min)(int(BT_MAX_THREAD_COUNT), 31);
- m_numThreads = ( std::max )( 1, ( std::min )( maxThreadCount, numThreads ) );
- using namespace concurrency;
- if ( CurrentScheduler::Id() != -1 )
- {
- CurrentScheduler::Detach();
- }
- SchedulerPolicy policy;
- {
- // PPL seems to destroy threads when threadpool is shrunk, but keeps reusing old threads
- // force it to destroy old threads
- policy.SetConcurrencyLimits( 1, 1 );
- CurrentScheduler::Create( policy );
- CurrentScheduler::Detach();
- }
- policy.SetConcurrencyLimits( m_numThreads, m_numThreads );
- CurrentScheduler::Create( policy );
- m_savedThreadCounter = 0;
- if ( m_isActive )
- {
- btResetThreadIndexCounter();
- }
- }
- struct BodyAdapter
- {
- const btIParallelForBody* mBody;
- int mGrainSize;
- int mIndexEnd;
-
- void operator()( int i ) const
- {
- BT_PROFILE( "PPL_job" );
- mBody->forLoop( i, ( std::min )( i + mGrainSize, mIndexEnd ) );
- }
- };
- virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE
- {
- BT_PROFILE( "parallelFor_PPL" );
- // PPL dispatch
- BodyAdapter pplBody;
- pplBody.mBody = &body;
- pplBody.mGrainSize = grainSize;
- pplBody.mIndexEnd = iEnd;
- btPushThreadsAreRunning();
- // note: MSVC 2010 doesn't support partitioner args, so avoid them
- concurrency::parallel_for( iBegin,
- iEnd,
- grainSize,
- pplBody
- );
- btPopThreadsAreRunning();
- }
-};
-#endif // #if BT_USE_PPL && BT_THREADSAFE
-
-
-// create a non-threaded task scheduler (always available)
-btITaskScheduler* btGetSequentialTaskScheduler()
-{
- static btTaskSchedulerSequential sTaskScheduler;
- return &sTaskScheduler;
-}
-
-
-// create an OpenMP task scheduler (if available, otherwise returns null)
-btITaskScheduler* btGetOpenMPTaskScheduler()
-{
-#if BT_USE_OPENMP && BT_THREADSAFE
- static btTaskSchedulerOpenMP sTaskScheduler;
- return &sTaskScheduler;
-#else
- return NULL;
-#endif
-}
-
-
-// create an Intel TBB task scheduler (if available, otherwise returns null)
-btITaskScheduler* btGetTBBTaskScheduler()
-{
-#if BT_USE_TBB && BT_THREADSAFE
- static btTaskSchedulerTBB sTaskScheduler;
- return &sTaskScheduler;
-#else
- return NULL;
-#endif
-}
-
-
-// create a PPL task scheduler (if available, otherwise returns null)
-btITaskScheduler* btGetPPLTaskScheduler()
-{
-#if BT_USE_PPL && BT_THREADSAFE
- static btTaskSchedulerPPL sTaskScheduler;
- return &sTaskScheduler;
-#else
- return NULL;
-#endif
-}
-