aFaces.push_back(aFace);
}
- OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel);
+ OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel, (Standard_Integer )aFaces.size());
}
update(aFaceIt.Value());
// Mesh faces
- OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel);
+ OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel, myFaces.Size());
commit();
clear();
OSD_OSDError.hxx
OSD_Parallel.cxx
OSD_Parallel.hxx
+OSD_Parallel_TBB.cxx
+OSD_Parallel_Threads.cxx
OSD_Path.cxx
OSD_Path.hxx
OSD_PerfMeter.cxx
OSD_SysType.hxx
OSD_Thread.cxx
OSD_Thread.hxx
+OSD_ThreadPool.cxx
+OSD_ThreadPool.hxx
OSD_ThreadFunction.hxx
OSD_Timer.cxx
OSD_Timer.hxx
//! user's code. Refer to Foundation Classes User's Guide for further details.
//!
Standard_EXPORT static void SetSignal (const Standard_Boolean theFloatingSignal = Standard_True);
-
+
+ //! Return floating signal catching value previously set by SetSignal().
+ Standard_EXPORT static Standard_Boolean ToCatchFloatingSignals();
+
//! Commands the process to sleep for a number of seconds.
Standard_EXPORT static void SecSleep (const Standard_Integer aDelay);
#ifndef OSD_Parallel_HeaderFile
#define OSD_Parallel_HeaderFile
-#include <OSD_Thread.hxx>
-#include <Standard_Mutex.hxx>
-#include <Standard_NotImplemented.hxx>
-#include <Standard_Atomic.hxx>
-#include <NCollection_Array1.hxx>
-
-#ifdef HAVE_TBB
-#include <tbb/parallel_for.h>
-#include <tbb/parallel_for_each.h>
-#include <tbb/blocked_range.h>
-#endif
+#include <Standard_Type.hxx>
+#include <memory>
+#include <type_traits>
-//! @class OSD_Parallel
-//! @brief Simplifies code parallelization.
+//! @brief Simple tool for code parallelization.
+//!
+//! OSD_Parallel class provides simple interface for parallel processing of
+//! tasks that can be formulated in terms of "for" or "foreach" loops.
+//!
+//! To use this tool it is necessary to:
+//! - organize the data to be processed in a collection accessible by
+//! iteration (usually array or vector);
+//! - implement a functor class providing operator () accepting iterator
+//! (or index in array) that does the job;
+//! - call either For() or ForEach() providing begin and end iterators and
+//! a functor object.
//!
-//! The Class provides an interface of parallel processing "for" and "foreach" loops.
-//! These primitives encapsulates complete logic for creating and managing parallel context of loops.
-//! Moreover the primitives may be a wrapper for some primitives from 3rd-party library - TBB.
-//! To use it is necessary to implement TBB like interface which is based on functors.
+//! Iterators should satisfy requirements of STL forward iterator.
+//! Functor
//!
//! @code
//! class Functor
//! };
//! @endcode
//!
-//! In the body of the operator () should be implemented thread-safe logic of computations that can be performed in parallel context.
-//! If parallelized loop iterates on the collections with direct access by index (such as Vector, Array),
-//! it is more efficient to use the primitive ParallelFor (because it has no critical section).
+//! The operator () should be implemented in a thread-safe way so that
+//! the same functor object can process different data items in parallel threads.
+//!
+//! Iteration by index (For) is expected to be more efficient than using iterators
+//! (ForEach).
+//!
+//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
+//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
+//! more efficient to use it directly instead of using OSD_Parallel.
+
class OSD_Parallel
{
- //! Auxiliary class which ensures exclusive
- //! access to iterators of processed data pool.
- template <typename Value>
- class Range
+private:
+
+ //! Interface class defining API for polymorphic wrappers over iterators.
+ //! Intended to add polymorphic behaviour to For and ForEach functionality
+ //! for arbitrary objects and eliminate dependency on template parameters.
+ class IteratorInterface
{
- public: //! @name public methods
+ public:
+ virtual ~IteratorInterface() {}
- typedef Value Iterator;
+ //! Returns true if iterators wrapped by this and theOther are equal
+ virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
- //! Constructor
- Range(const Value& theBegin, const Value& theEnd)
- : myBegin(theBegin),
- myEnd (theEnd),
- myIt (theBegin)
- {
- }
+ //! Increments wrapped iterator
+ virtual void Increment () = 0;
+
+ //! Returns new instance of the wrapper containing copy
+ //! of the wrapped iterator.
+ virtual IteratorInterface* Clone() const = 0;
+ };
- //! Returns const link on the first element.
- inline const Value& Begin() const
+ //! Implementation of polymorphic iterator wrapper suitable for basic
+ //! types as well as for std iterators.
+ //! Wraps instance of actual iterator type Type.
+ template<class Type>
+ class IteratorWrapper : public IteratorInterface
+ {
+ public:
+ IteratorWrapper() {}
+ IteratorWrapper(const Type& theValue) : myValue(theValue) {}
+
+ virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
{
- return myBegin;
+ return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
}
- //! Returns const link on the last element.
- inline const Value& End() const
+ virtual void Increment () Standard_OVERRIDE
{
- return myEnd;
+ ++myValue;
}
- //! Returns first non processed element or end.
- //! Thread-safe method.
- inline Iterator It() const
+ virtual IteratorInterface* Clone() const Standard_OVERRIDE
{
- Standard_Mutex::Sentry aMutex( myMutex );
- return ( myIt != myEnd ) ? myIt++ : myEnd;
+ return new IteratorWrapper<Type>(myValue);
}
- private: //! @name private methods
-
- //! Empty copy constructor
- Range(const Range& theCopy);
+ const Type& Value() const { return myValue; }
- //! Empty copy operator.
- Range& operator=(const Range& theCopy);
-
- private: //! @name private fields
-
- const Value& myBegin; //!< Fisrt element of range.
- const Value& myEnd; //!< Last element of range.
- mutable Value myIt; //!< First non processed element of range.
- mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
+ private:
+ Type myValue;
};
- //! Auxiliary wrapper class for thread function.
- template <typename Functor, typename InputIterator>
- class Task
+protected:
+ // Note: UniversalIterator and FunctorInterface are made protected to be
+ // accessible from specialization using threads (non-TBB).
+
+ //! Fixed-type iterator, implementing STL forward iterator interface, used for
+ //! iteration over objects subject to parallel processing.
+ //! It stores pointer to instance of polymorphic iterator inheriting from
+ //! IteratorInterface, which contains actual type-specific iterator.
+ class UniversalIterator :
+ // Note that TBB requires that value_type of iterator be copyable,
+ // thus we use its own type for that
+ public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
{
- public: //! @name public methods
+ public:
+ UniversalIterator() {}
- //! Constructor.
- Task(const Functor& thePerformer, Range<InputIterator>& theRange)
- : myPerformer(thePerformer),
- myRange (theRange)
+ UniversalIterator(IteratorInterface* theOther)
+ : myPtr(theOther)
{
}
- //! Method is executed in the context of thread,
- //! so this method defines the main calculations.
- static Standard_Address RunWithIterator(Standard_Address theTask)
+ UniversalIterator(const UniversalIterator& theOther)
+ : myPtr (theOther.myPtr->Clone())
{
- Task<Functor, InputIterator>& aTask =
- *( static_cast< Task<Functor, InputIterator>* >(theTask) );
+ }
- const Range<InputIterator>& aData( aTask.myRange );
- typename Range<InputIterator>::Iterator i = aData.It();
+ UniversalIterator& operator= (const UniversalIterator& theOther)
+ {
+ myPtr.reset (theOther.myPtr->Clone());
+ return *this;
+ }
- for ( ; i != aData.End(); i = aData.It() )
- {
- aTask.myPerformer(*i);
- }
+ bool operator!= (const UniversalIterator& theOther) const
+ {
+ return ! myPtr->IsEqual (*theOther.myPtr);
+ }
- return NULL;
+ bool operator== (const UniversalIterator& theOther) const
+ {
+ return myPtr->IsEqual (*theOther.myPtr);
}
- //! Method is executed in the context of thread,
- //! so this method defines the main calculations.
- static Standard_Address RunWithIndex(Standard_Address theTask)
+ UniversalIterator& operator++()
{
- Task<Functor, InputIterator>& aTask =
- *( static_cast< Task<Functor, Standard_Integer>* >(theTask) );
+ myPtr->Increment();
+ return *this;
+ }
+
+ UniversalIterator operator++(int)
+ {
+ UniversalIterator aValue(*this);
+ myPtr->Increment();
+ return aValue;
+ }
- const Range<Standard_Integer>& aData( aTask.myRange );
- Standard_Integer i = aData.It();
+ const UniversalIterator& operator* () const { return *this; }
+ UniversalIterator& operator* () { return *this; }
- for ( ; i < aData.End(); i = aData.It())
- {
- aTask.myPerformer(i);
- }
+ const UniversalIterator* operator->() const { return this; }
+ UniversalIterator* operator->() { return this; }
- return NULL;
+ // type cast to actual iterator
+ template <typename Iterator>
+ const Iterator& DownCast () const
+ {
+ return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
}
- private: //! @name private methods
+ private:
+#if (defined(_MSC_VER) && (_MSC_VER < 1600))
+ std::auto_ptr<IteratorInterface> myPtr;
+#else
+ std::unique_ptr<IteratorInterface> myPtr;
+#endif
+ };
- //! Empty copy constructor.
- Task(const Task& theCopy);
+ //! Interface class representing functor object.
+ //! Intended to add polymorphic behavour to For and ForEach functionality
+ //! enabling execution of arbitrary function in parallel mode.
+ class FunctorInterface
+ {
+ public:
+ virtual ~FunctorInterface() {}
- //! Empty copy operator.
- Task& operator=(const Task& theCopy);
+ virtual void operator () (UniversalIterator& theIterator) const = 0;
+ };
- private: //! @name private fields
+private:
- const Functor& myPerformer; //!< Link on functor.
- const Range<InputIterator>& myRange; //!< Link on processed data block.
+ //! Wrapper for functors manipulating on std iterators.
+ template<class Iterator, class Functor>
+ class FunctorWrapperIter : public FunctorInterface
+ {
+ public:
+ FunctorWrapperIter (const Functor& theFunctor)
+ : myFunctor(theFunctor)
+ {
+ }
+
+ virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
+ {
+ const Iterator& anIt = theIterator.DownCast<Iterator>();
+ myFunctor(*anIt);
+ }
+
+ private:
+ FunctorWrapperIter (const FunctorWrapperIter&);
+ void operator = (const FunctorWrapperIter&);
+ const Functor& myFunctor;
};
-public: //! @name public methods
+ //! Wrapper for functors manipulating on integer index.
+ template<class Functor>
+ class FunctorWrapperInt : public FunctorInterface
+ {
+ public:
+ FunctorWrapperInt (const Functor& theFunctor)
+ : myFunctor(theFunctor)
+ {
+ }
- //! Returns number of logical proccesrs.
- Standard_EXPORT static Standard_Integer NbLogicalProcessors();
+ virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
+ {
+ Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
+ myFunctor(anIndex);
+ }
+
+ private:
+ FunctorWrapperInt (const FunctorWrapperInt&);
+ void operator = (const FunctorWrapperInt&);
+ const Functor& myFunctor;
+ };
+
+private:
//! Simple primitive for parallelization of "foreach" loops, e.g.:
//! @code
//! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
//! @endcode
+ //! Implementation of framework-dependent functionality should be provided by
+ //! forEach_impl function defined in opencascade::parallel namespace.
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
- //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}" performing task for specified iterator position
- //! @param isForceSingleThreadExecution if true, then no threads will be created
- template <typename InputIterator, typename Functor>
- static void ForEach( InputIterator theBegin,
- InputIterator theEnd,
- const Functor& theFunctor,
- const Standard_Boolean isForceSingleThreadExecution
- = Standard_False );
+ //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
+ //! performing task for the specified iterator position
+ //! @param theNbItems number of items passed by iterator, -1 if unknown
+ Standard_EXPORT static void forEach (UniversalIterator& theBegin,
+ UniversalIterator& theEnd,
+ const FunctorInterface& theFunctor,
+ Standard_Integer theNbItems);
+
+public: //! @name public methods
+
+ //! Returns number of logical proccesrs.
+ Standard_EXPORT static Standard_Integer NbLogicalProcessors();
- //! Simple primitive for parallelization of "for" loops, e.g.:
+ //! Simple primitive for parallelization of "foreach" loops, equivalent to:
//! @code
- //! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
+ //! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
+ //! theFunctor(*anIter);
+ //! }
//! @endcode
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
- //! @param theFunctor functor providing an interface "void operator(int theIndex){}" performing task for specified index
+ //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
+ //! performing task for specified iterator position
//! @param isForceSingleThreadExecution if true, then no threads will be created
- template <typename Functor>
- static void For( const Standard_Integer theBegin,
- const Standard_Integer theEnd,
- const Functor& theFunctor,
- const Standard_Boolean isForceSingleThreadExecution
- = Standard_False );
-};
-
-//=======================================================================
-//function : OSD_Parallel::Range::It
-//purpose : Template concretization.
-//=======================================================================
-template<> inline Standard_Integer OSD_Parallel::Range<Standard_Integer>::It() const
-{
- return Standard_Atomic_Increment( reinterpret_cast<volatile int*>(&myIt) ) - 1;
-}
-
-//=======================================================================
-//function : ParallelForEach
-//purpose :
-//=======================================================================
-template <typename InputIterator, typename Functor>
-void OSD_Parallel::ForEach( InputIterator theBegin,
- InputIterator theEnd,
- const Functor& theFunctor,
- const Standard_Boolean isForceSingleThreadExecution )
-{
- if ( isForceSingleThreadExecution )
- {
- for ( InputIterator it(theBegin); it != theEnd; ++it )
- theFunctor(*it);
-
- return;
- }
- #ifdef HAVE_TBB
+ //! @param theNbItems number of items passed by iterator, -1 if unknown
+ template <typename InputIterator, typename Functor>
+ static void ForEach(InputIterator theBegin,
+ InputIterator theEnd,
+ const Functor& theFunctor,
+ const Standard_Boolean isForceSingleThreadExecution = Standard_False,
+ Standard_Integer theNbItems = -1)
{
- try
+ if (isForceSingleThreadExecution || theNbItems == 1)
{
- tbb::parallel_for_each(theBegin, theEnd, theFunctor);
+ for (InputIterator it(theBegin); it != theEnd; ++it)
+ theFunctor(*it);
}
- catch ( tbb::captured_exception& anException )
+ else
{
- throw Standard_NotImplemented(anException.what());
+ UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
+ UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
+ FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
+ forEach(aBegin, aEnd, aFunctor, theNbItems);
}
}
- #else
- {
- Range<InputIterator> aData(theBegin, theEnd);
- Task<Functor, InputIterator> aTask(theFunctor, aData);
-
- const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
- NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
- for ( Standard_Integer i = 0; i < aNbThreads; ++i )
- {
- OSD_Thread& aThread = aThreads(i);
- aThread.SetFunction(&Task<Functor, InputIterator>::RunWithIterator);
- aThread.Run(&aTask);
- }
-
- for ( Standard_Integer i = 0; i < aNbThreads; ++i )
- aThreads(i).Wait();
- }
- #endif
-}
-
-//=======================================================================
-//function : ParallelFor
-//purpose :
-//=======================================================================
-template <typename Functor>
-void OSD_Parallel::For( const Standard_Integer theBegin,
- const Standard_Integer theEnd,
- const Functor& theFunctor,
- const Standard_Boolean isForceSingleThreadExecution )
-{
- if ( isForceSingleThreadExecution )
- {
- for ( Standard_Integer i = theBegin; i < theEnd; ++i )
- theFunctor(i);
-
- return;
- }
- #ifdef HAVE_TBB
+ //! Simple primitive for parallelization of "for" loops, equivalent to:
+ //! @code
+ //! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
+ //! theFunctor(anIter);
+ //! }
+ //! @endcode
+ //! @param theBegin the first index (incusive)
+ //! @param theEnd the last index (exclusive)
+ //! @param theFunctor functor providing an interface "void operator(int theIndex){}"
+ //! performing task for specified index
+ //! @param isForceSingleThreadExecution if true, then no threads will be created
+ template <typename Functor>
+ static void For(const Standard_Integer theBegin,
+ const Standard_Integer theEnd,
+ const Functor& theFunctor,
+ const Standard_Boolean isForceSingleThreadExecution = Standard_False)
{
- try
+ if (isForceSingleThreadExecution || (theEnd - theBegin) == 1)
{
- tbb::parallel_for( theBegin, theEnd, theFunctor );
+ for (Standard_Integer it (theBegin); it != theEnd; ++it)
+ theFunctor(it);
}
- catch ( tbb::captured_exception& anException )
+ else
{
- throw Standard_NotImplemented(anException.what());
+ UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
+ UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
+ FunctorWrapperInt<Functor> aFunctor (theFunctor);
+ forEach(aBegin, aEnd, aFunctor, theEnd - theBegin);
}
}
- #else
- {
- Range<Standard_Integer> aData(theBegin, theEnd);
- Task<Functor, Standard_Integer> aTask(theFunctor, aData);
-
- const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
- NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
- for ( Standard_Integer i = 0; i < aNbThreads; ++i )
- {
- OSD_Thread& aThread = aThreads(i);
- aThread.SetFunction(&Task<Functor, Standard_Integer>::RunWithIndex);
- aThread.Run(&aTask);
- }
-
- for ( Standard_Integer i = 0; i < aNbThreads; ++i )
- aThreads(i).Wait();
- }
- #endif
-}
+};
#endif
--- /dev/null
+// Created on: 2014-08-19
+// Created by: Alexander Zaikin
+// Copyright (c) 1996-1999 Matra Datavision
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+// Version of parallel executor used when TBB is available
+#ifdef HAVE_TBB
+
+#include <OSD_Parallel.hxx>
+#include <Standard_ProgramError.hxx>
+
+#include <tbb/parallel_for.h>
+#include <tbb/parallel_for_each.h>
+#include <tbb/blocked_range.h>
+
+//=======================================================================
+//function : forEach
+//purpose :
+//=======================================================================
+
+void OSD_Parallel::forEach (UniversalIterator& theBegin,
+ UniversalIterator& theEnd,
+ const FunctorInterface& theFunctor,
+ Standard_Integer theNbItems)
+{
+ (void )theNbItems;
+ try
+ {
+ tbb::parallel_for_each(theBegin, theEnd, theFunctor);
+ }
+ catch (tbb::captured_exception& anException)
+ {
+ throw Standard_ProgramError(anException.what());
+ }
+}
+
+#endif /* HAVE_TBB */
\ No newline at end of file
--- /dev/null
+// Created on: 2014-08-19
+// Created by: Alexander Zaikin
+// Copyright (c) 1996-1999 Matra Datavision
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+// Version of parallel executor used when TBB is not available
+#ifndef HAVE_TBB
+
+#include <OSD_Parallel.hxx>
+
+#include <OSD_ThreadPool.hxx>
+
+#include <NCollection_Array1.hxx>
+#include <Standard_Mutex.hxx>
+#include <OSD_Thread.hxx>
+
+namespace
+{
+ //! Class implementing tools for parallel processing
+ //! using threads (when TBB is not available);
+ //! it is derived from OSD_Parallel to get access to
+ //! Iterator and FunctorInterface nested types.
+ class OSD_Parallel_Threads : public OSD_ThreadPool, public OSD_Parallel
+ {
+ public:
+ //! Auxiliary class which ensures exclusive
+ //! access to iterators of processed data pool.
+ class Range
+ {
+ public: //! @name public methods
+
+ //! Constructor
+ Range(const OSD_Parallel::UniversalIterator& theBegin,
+ const OSD_Parallel::UniversalIterator& theEnd)
+ : myBegin(theBegin),
+ myEnd(theEnd),
+ myIt(theBegin)
+ {
+ }
+
+ //! Returns const link on the first element.
+ inline const OSD_Parallel::UniversalIterator& Begin() const
+ {
+ return myBegin;
+ }
+
+ //! Returns const link on the last element.
+ inline const OSD_Parallel::UniversalIterator& End() const
+ {
+ return myEnd;
+ }
+
+ //! Returns first non processed element or end.
+ //! Thread-safe method.
+ inline OSD_Parallel::UniversalIterator It() const
+ {
+ Standard_Mutex::Sentry aMutex(myMutex);
+ return (myIt != myEnd) ? myIt++ : myEnd;
+ }
+
+ private: //! @name private methods
+
+ //! Empty copy constructor
+ Range(const Range& theCopy);
+
+ //! Empty copy operator.
+ Range& operator=(const Range& theCopy);
+
+ private: //! @name private fields
+
+ const OSD_Parallel::UniversalIterator& myBegin; //!< Fisrt element of range.
+ const OSD_Parallel::UniversalIterator& myEnd; //!< Last element of range.
+ mutable OSD_Parallel::UniversalIterator myIt; //!< First non processed element of range.
+ mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
+ };
+
+ //! Auxiliary wrapper class for thread function.
+ class Task : public JobInterface
+ {
+ public: //! @name public methods
+
+ //! Constructor.
+ Task(const OSD_Parallel::FunctorInterface& thePerformer, Range& theRange)
+ : myPerformer(thePerformer),
+ myRange(theRange)
+ {
+ }
+
+ //! Method is executed in the context of thread,
+ //! so this method defines the main calculations.
+ virtual void Perform (int ) Standard_OVERRIDE
+ {
+ for (OSD_Parallel::UniversalIterator anIter = myRange.It(); anIter != myRange.End(); anIter = myRange.It())
+ {
+ myPerformer (anIter);
+ }
+ }
+
+ private: //! @name private methods
+
+ //! Empty copy constructor.
+ Task(const Task& theCopy);
+
+ //! Empty copy operator.
+ Task& operator=(const Task& theCopy);
+
+ private: //! @name private fields
+ const FunctorInterface& myPerformer; //!< Link on functor
+ const Range& myRange; //!< Link on processed data block
+ };
+
+ //! Launcher specialization.
+ class UniversalLauncher : public Launcher
+ {
+ public:
+ //! Constructor.
+ UniversalLauncher (OSD_ThreadPool& thePool, int theMaxThreads = -1)
+ : Launcher (thePool, theMaxThreads) {}
+
+ //! Primitive for parallelization of "for" loops.
+ void Perform (OSD_Parallel::UniversalIterator& theBegin,
+ OSD_Parallel::UniversalIterator& theEnd,
+ const OSD_Parallel::FunctorInterface& theFunctor)
+ {
+ Range aData (theBegin, theEnd);
+ Task aJob (theFunctor, aData);
+ perform (aJob);
+ }
+ };
+ };
+}
+
+//=======================================================================
+//function : forEach
+//purpose :
+//=======================================================================
+void OSD_Parallel::forEach (UniversalIterator& theBegin,
+ UniversalIterator& theEnd,
+ const FunctorInterface& theFunctor,
+ Standard_Integer theNbItems)
+{
+ const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
+ const Standard_Integer aNbThreads = theNbItems != -1 ? Min (theNbItems, aThreadPool->NbDefaultThreadsToLaunch()) : -1;
+ OSD_Parallel_Threads::UniversalLauncher aLauncher (*aThreadPool, aNbThreads);
+ aLauncher.Perform (theBegin, theEnd, theFunctor);
+}
+
+#endif /* ! HAVE_TBB */
--- /dev/null
+// Created by: Kirill Gavrilov
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of commercial software by OPEN CASCADE SAS.
+//
+// This software is furnished in accordance with the terms and conditions
+// of the contract and with the inclusion of this copyright notice.
+// This software or any other copy thereof may not be provided or otherwise
+// be made available to any third party.
+// No ownership title to the software is transferred hereby.
+//
+// OPEN CASCADE SAS makes no representation or warranties with respect to the
+// performance of this software, and specifically disclaims any responsibility
+// for any damages, special or consequential, connected with its use.
+
+#include <OSD_ThreadPool.hxx>
+
+#include <OSD.hxx>
+#include <Standard_Atomic.hxx>
+#include <TCollection_AsciiString.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
+
+// =======================================================================
+// function : Lock
+// purpose :
+// =======================================================================
+bool OSD_ThreadPool::EnumeratedThread::Lock()
+{
+ return Standard_Atomic_CompareAndSwap (&myUsageCounter, 0, 1);
+}
+
+// =======================================================================
+// function : Free
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::EnumeratedThread::Free()
+{
+ Standard_Atomic_CompareAndSwap (&myUsageCounter, 1, 0);
+}
+
+// =======================================================================
+// function : WakeUp
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::EnumeratedThread::WakeUp (JobInterface* theJob, bool theToCatchFpe)
+{
+ myJob = theJob;
+ myToCatchFpe = theToCatchFpe;
+ if (myIsSelfThread)
+ {
+ if (theJob != NULL)
+ {
+ OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
+ }
+ return;
+ }
+
+ myWakeEvent.Set();
+ if (theJob != NULL && !myIsStarted)
+ {
+ myIsStarted = true;
+ Run (this);
+ }
+}
+
+// =======================================================================
+// function : WaitIdle
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::EnumeratedThread::WaitIdle()
+{
+ if (!myIsSelfThread)
+ {
+ myIdleEvent.Wait();
+ myIdleEvent.Reset();
+ }
+}
+
+// =======================================================================
+// function : DefaultPool
+// purpose :
+// =======================================================================
+const Handle(OSD_ThreadPool)& OSD_ThreadPool::DefaultPool (int theNbThreads)
+{
+ static const Handle(OSD_ThreadPool) THE_GLOBAL_POOL = new OSD_ThreadPool (theNbThreads);
+ return THE_GLOBAL_POOL;
+}
+
+// =======================================================================
+// function : OSD_ThreadPool
+// purpose :
+// =======================================================================
+OSD_ThreadPool::OSD_ThreadPool (int theNbThreads)
+: myNbDefThreads (0),
+ myShutDown (false)
+{
+ Init (theNbThreads);
+ myNbDefThreads = NbThreads();
+}
+
+// =======================================================================
+// function : IsInUse
+// purpose :
+// =======================================================================
+bool OSD_ThreadPool::IsInUse()
+{
+ for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
+ aThreadIter.More(); aThreadIter.Next())
+ {
+ EnumeratedThread& aThread = aThreadIter.ChangeValue();
+ if (!aThread.Lock())
+ {
+ return true;
+ }
+ aThread.Free();
+ }
+ return false;
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::Init (int theNbThreads)
+{
+ const int aNbThreads = Max (0, (theNbThreads > 0 ? theNbThreads : OSD_Parallel::NbLogicalProcessors()) - 1);
+ if (myThreads.Size() == aNbThreads)
+ {
+ return;
+ }
+
+ // release old threads
+ if (!myThreads.IsEmpty())
+ {
+ NCollection_Array1<EnumeratedThread*> aLockThreads (myThreads.Lower(), myThreads.Upper());
+ aLockThreads.Init (NULL);
+ int aThreadIndex = myThreads.Lower();
+ for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
+ aThreadIter.More(); aThreadIter.Next())
+ {
+ EnumeratedThread& aThread = aThreadIter.ChangeValue();
+ if (!aThread.Lock())
+ {
+ for (NCollection_Array1<EnumeratedThread*>::Iterator aLockThreadIter (aLockThreads);
+ aLockThreadIter.More() && aLockThreadIter.Value() != NULL; aLockThreadIter.Next())
+ {
+ aLockThreadIter.ChangeValue()->Free();
+ }
+ throw Standard_ProgramError ("Error: active ThreadPool is reinitialized");
+ }
+ aLockThreads.SetValue (aThreadIndex++, &aThread);
+ }
+ }
+ release();
+
+ myShutDown = false;
+ if (aNbThreads > 0)
+ {
+ myThreads.Resize (0, aNbThreads - 1, false);
+ int aLastThreadIndex = 0;
+ for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
+ aThreadIter.More(); aThreadIter.Next())
+ {
+ EnumeratedThread& aThread = aThreadIter.ChangeValue();
+ aThread.myPool = this;
+ aThread.myThreadIndex = aLastThreadIndex++;
+ aThread.SetFunction (&OSD_ThreadPool::EnumeratedThread::runThread);
+ }
+ }
+ else
+ {
+ NCollection_Array1<EnumeratedThread> anEmpty;
+ myThreads.Move (anEmpty);
+ }
+}
+
+// =======================================================================
+// function : ~OSD_ThreadPool
+// purpose :
+// =======================================================================
+OSD_ThreadPool::~OSD_ThreadPool()
+{
+ release();
+}
+
+// =======================================================================
+// function : release
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::release()
+{
+ if (myThreads.IsEmpty())
+ {
+ return;
+ }
+
+ myShutDown = true;
+ for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
+ aThreadIter.More(); aThreadIter.Next())
+ {
+ aThreadIter.ChangeValue().WakeUp (NULL, false);
+ aThreadIter.ChangeValue().Wait();
+ }
+}
+
+// =======================================================================
+// function : perform
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::Launcher::perform (JobInterface& theJob)
+{
+ run (theJob);
+ wait();
+}
+
+// =======================================================================
+// function : run
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::Launcher::run (JobInterface& theJob)
+{
+ bool toCatchFpe = OSD::ToCatchFloatingSignals();
+ for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
+ aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
+ {
+ aThreadIter.ChangeValue()->WakeUp (&theJob, toCatchFpe);
+ }
+}
+
+// =======================================================================
+// function : wait
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::Launcher::wait()
+{
+ int aNbFailures = 0;
+ for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
+ aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
+ {
+ aThreadIter.ChangeValue()->WaitIdle();
+ if (!aThreadIter.Value()->myFailure.IsNull())
+ {
+ ++aNbFailures;
+ }
+ }
+ if (aNbFailures == 0)
+ {
+ return;
+ }
+
+ TCollection_AsciiString aFailures;
+ for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
+ aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
+ {
+ if (!aThreadIter.Value()->myFailure.IsNull())
+ {
+ if (aNbFailures == 1)
+ {
+ aThreadIter.Value()->myFailure->Reraise();
+ }
+
+ if (!aFailures.IsEmpty())
+ {
+ aFailures += "\n";
+ }
+ aFailures += aThreadIter.Value()->myFailure->GetMessageString();
+ }
+ }
+
+ aFailures = TCollection_AsciiString("Multiple exceptions:\n") + aFailures;
+ throw Standard_ProgramError (aFailures.ToCString());
+}
+
+// =======================================================================
+// function : performJob
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::performJob (Handle(Standard_Failure)& theFailure,
+ OSD_ThreadPool::JobInterface* theJob,
+ int theThreadIndex)
+{
+ try
+ {
+ OCC_CATCH_SIGNALS
+ theJob->Perform (theThreadIndex);
+ }
+ catch (Standard_Failure const& aFailure)
+ {
+ TCollection_AsciiString aMsg = TCollection_AsciiString (aFailure.DynamicType()->Name())
+ + ": " + aFailure.GetMessageString();
+ theFailure = new Standard_ProgramError (aMsg.ToCString());
+ }
+ catch (std::exception& anStdException)
+ {
+ TCollection_AsciiString aMsg = TCollection_AsciiString (typeid(anStdException).name())
+ + ": " + anStdException.what();
+ theFailure = new Standard_ProgramError (aMsg.ToCString());
+ }
+ catch (...)
+ {
+ theFailure = new Standard_ProgramError ("Error: Unknown exception");
+ }
+}
+
+// =======================================================================
+// function : performThread
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::EnumeratedThread::performThread()
+{
+ OSD::SetSignal (false);
+ for (;;)
+ {
+ myWakeEvent.Wait();
+ myWakeEvent.Reset();
+ if (myPool->myShutDown)
+ {
+ return;
+ }
+
+ myFailure.Nullify();
+ if (myJob != NULL)
+ {
+ OSD::SetSignal (myToCatchFpe);
+ OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
+ myJob = NULL;
+ }
+ myIdleEvent.Set();
+ }
+}
+
+// =======================================================================
+// function : runThread
+// purpose :
+// =======================================================================
+Standard_Address OSD_ThreadPool::EnumeratedThread::runThread (Standard_Address theTask)
+{
+ EnumeratedThread* aThread = static_cast<EnumeratedThread*>(theTask);
+ aThread->performThread();
+ return NULL;
+}
+
+// =======================================================================
+// function : Launcher
+// purpose :
+// =======================================================================
+OSD_ThreadPool::Launcher::Launcher (OSD_ThreadPool& thePool, Standard_Integer theMaxThreads)
+: mySelfThread (true),
+ myNbThreads (0)
+{
+ const int aNbThreads = theMaxThreads > 0
+ ? Min (theMaxThreads, thePool.NbThreads())
+ : (theMaxThreads < 0
+ ? Max (thePool.NbDefaultThreadsToLaunch(), 1)
+ : 1);
+ myThreads.Resize (0, aNbThreads - 1, false);
+ myThreads.Init (NULL);
+ if (aNbThreads > 1)
+ {
+ for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (thePool.myThreads);
+ aThreadIter.More(); aThreadIter.Next())
+ {
+ if (aThreadIter.ChangeValue().Lock())
+ {
+ myThreads.SetValue (myNbThreads, &aThreadIter.ChangeValue());
+ // make thread index to fit into myThreads range
+ aThreadIter.ChangeValue().myThreadIndex = myNbThreads;
+ if (++myNbThreads == aNbThreads - 1)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // self thread should be executed last
+ myThreads.SetValue (myNbThreads, &mySelfThread);
+ mySelfThread.myThreadIndex = myNbThreads;
+ ++myNbThreads;
+}
+
+// =======================================================================
+// function : Release
+// purpose :
+// =======================================================================
+void OSD_ThreadPool::Launcher::Release()
+{
+ for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
+ aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
+ {
+ if (aThreadIter.Value() != &mySelfThread)
+ {
+ aThreadIter.Value()->Free();
+ }
+ }
+
+ NCollection_Array1<EnumeratedThread*> anEmpty;
+ myThreads.Move (anEmpty);
+ myNbThreads = 0;
+}
--- /dev/null
+// Created by: Kirill Gavrilov
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of commercial software by OPEN CASCADE SAS.
+//
+// This software is furnished in accordance with the terms and conditions
+// of the contract and with the inclusion of this copyright notice.
+// This software or any other copy thereof may not be provided or otherwise
+// be made available to any third party.
+// No ownership title to the software is transferred hereby.
+//
+// OPEN CASCADE SAS makes no representation or warranties with respect to the
+// performance of this software, and specifically disclaims any responsibility
+// for any damages, special or consequential, connected with its use.
+
+#ifndef _OSD_ThreadPool_HeaderFile
+#define _OSD_ThreadPool_HeaderFile
+
+#include <NCollection_Array1.hxx>
+#include <OSD_Thread.hxx>
+#include <OSD_Parallel.hxx>
+#include <Standard_Atomic.hxx>
+#include <Standard_Condition.hxx>
+#include <Standard_Mutex.hxx>
+
+//! Class defining a thread pool for executing algorithms in multi-threaded mode.
+//! Thread pool allocates requested amount of threads and keep them alive
+//! (in sleep mode when unused) during thread pool lifetime.
+//! The same pool can be used by multiple consumers,
+//! including nested multi-threading algorithms and concurrent threads:
+//! - Thread pool can be used either by multi-threaded algorithm by creating OSD_ThreadPool::Launcher.
+//! The functor performing a job takes two parameters - Thread Index and Data Index:
+//! void operator(int theThreadIndex, int theDataIndex){}
+//! Multi-threaded algorithm may rely on Thread Index for allocating thread-local variables in array form,
+//! since the Thread Index is guaranteed to be within range OSD_ThreadPool::Lower() and OSD_ThreadPool::Upper().
+//! - Default thread pool (OSD_ThreadPool::DefaultPool()) can be used in general case,
+//! but application may prefer creating a dedicated pool for better control.
+//! - Default thread pool allocates the amount of threads considering concurrency
+//! level of the system (amount of logical processors).
+//! This can be overridden during OSD_ThreadPool construction or by calling OSD_ThreadPool::Init()
+//! (the pool should not be used!).
+//! - OSD_ThreadPool::Launcher reserves specific amount of threads from the pool for executing multi-threaded Job.
+//! Normally, single Launcher instance will occupy all threads available in thread pool,
+//! so that nested multi-threaded algorithms (within the same thread)
+//! and concurrent threads trying to use the same thread pool will run sequentially.
+//! This behavior is affected by OSD_ThreadPool::NbDefaultThreadsToLaunch() parameter
+//! and Launcher constructor, so that single Launcher instance will occupy not all threads
+//! in the pool allowing other threads to be used concurrently.
+//! - OSD_ThreadPool::Launcher locks thread one-by-one from thread pool in a thread-safe way.
+//! - Each working thread catches exceptions occurred during job execution, and Launcher will
+//! throw Standard_Failure in a caller thread on completed execution.
+class OSD_ThreadPool : public Standard_Transient
+{
+ DEFINE_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
+public:
+
+ //! Return (or create) a default thread pool.
+ //! Number of threads argument will be considered only when called first time.
+ Standard_EXPORT static const Handle(OSD_ThreadPool)& DefaultPool (int theNbThreads = -1);
+
+public:
+
+ //! Main constructor.
+ //! Application may consider specifying more threads than actually
+ //! available (OSD_Parallel::NbLogicalProcessors()) and set up NbDefaultThreadsToLaunch() to a smaller value
+ //! so that concurrent threads will be able using single Thread Pool instance more efficiently.
+ //! @param theNbThreads threads number to be created by pool
+ //! (if -1 is specified then OSD_Parallel::NbLogicalProcessors() will be used)
+ Standard_EXPORT OSD_ThreadPool (int theNbThreads = -1);
+
+ //! Destructor.
+ Standard_EXPORT virtual ~OSD_ThreadPool();
+
+ //! Return TRUE if at least 2 threads are available (including self-thread).
+ bool HasThreads() const { return NbThreads() >= 2; }
+
+ //! Return the lower thread index.
+ int LowerThreadIndex() const { return 0; }
+
+ //! Return the upper thread index (last index is reserved for self-thread).
+ int UpperThreadIndex() const { return LowerThreadIndex() + myThreads.Size(); }
+
+ //! Return the number of threads; >= 1.
+ int NbThreads() const { return myThreads.Size() + 1; }
+
+ //! Return maximum number of threads to be locked by a single Launcher object by default;
+ //! the entire thread pool size is returned by default.
+ int NbDefaultThreadsToLaunch() const { return myNbDefThreads; }
+
+ //! Set maximum number of threads to be locked by a single Launcher object by default.
+ //! Should be set BEFORE first usage.
+ void SetNbDefaultThreadsToLaunch (int theNbThreads) { myNbDefThreads = theNbThreads; }
+
+ //! Checks if thread pools has active consumers.
+ Standard_EXPORT bool IsInUse();
+
+ //! Reinitialize the thread pool with a different number of threads.
+ //! Should be called only with no active jobs, or exception Standard_ProgramError will be thrown!
+ Standard_EXPORT void Init (int theNbThreads);
+
+protected:
+
+ //! Thread function interface.
+ class JobInterface
+ {
+ public:
+ virtual void Perform (int theThreadIndex) = 0;
+ };
+
+ //! Thread with back reference to thread pool and thread index in it.
+ class EnumeratedThread : public OSD_Thread
+ {
+ friend class OSD_ThreadPool;
+ public:
+ EnumeratedThread (bool theIsSelfThread = false)
+ : myPool (NULL), myJob (NULL), myWakeEvent (false),
+ myIdleEvent (false), myThreadIndex (0), myUsageCounter(0),
+ myIsStarted (false), myToCatchFpe (false),
+ myIsSelfThread (theIsSelfThread) {}
+
+ //! Occupy this thread for thread pool launcher.
+ //! @return TRUE on success, or FALSE if thread has been already occupied
+ Standard_EXPORT bool Lock();
+
+ //! Release this thread for thread pool launcher; should be called only after successful OccupyThread().
+ Standard_EXPORT void Free();
+
+ //! Wake up the thread.
+ Standard_EXPORT void WakeUp (JobInterface* theJob, bool theToCatchFpe);
+
+ //! Wait the thread going into Idle state (finished jobs).
+ Standard_EXPORT void WaitIdle();
+
+ private:
+
+ //! Method is executed in the context of thread.
+ void performThread();
+
+ //! Method is executed in the context of thread.
+ static Standard_Address runThread (Standard_Address theTask);
+
+ private:
+ OSD_ThreadPool* myPool;
+ JobInterface* myJob;
+ Handle(Standard_Failure) myFailure;
+ Standard_Condition myWakeEvent;
+ Standard_Condition myIdleEvent;
+ int myThreadIndex;
+ volatile int myUsageCounter;
+ bool myIsStarted;
+ bool myToCatchFpe;
+ bool myIsSelfThread;
+ };
+
+public:
+
+ //! Launcher object locking a subset of threads (or all threads)
+ //! in a thread pool to perform parallel execution of the job.
+ class Launcher
+ {
+ public:
+ //! Lock specified number of threads from the thread pool.
+ //! If thread pool is already locked by another user,
+ //! Launcher will lock as many threads as possible
+ //! (if none will be locked, then single threaded execution will be done).
+ //! @param thePool thread pool to lock the threads
+ //! @param theMaxThreads number of threads to lock;
+ //! -1 specifies that default number of threads
+ //! to be used OSD_ThreadPool::NbDefaultThreadsToLaunch()
+ Standard_EXPORT Launcher (OSD_ThreadPool& thePool, int theMaxThreads = -1);
+
+ //! Release threads.
+ ~Launcher() { Release(); }
+
+ //! Return TRUE if at least 2 threads have been locked for parallel execution (including self-thread);
+ //! otherwise, the functor will be executed within the caller thread.
+ bool HasThreads() const { return myNbThreads >= 2; }
+
+ //! Return amount of locked threads; >= 1.
+ int NbThreads() const { return myNbThreads; }
+
+ //! Return the lower thread index.
+ int LowerThreadIndex() const { return 0; }
+
+ //! Return the upper thread index (last index is reserved for the self-thread).
+ int UpperThreadIndex() const { return LowerThreadIndex() + myNbThreads - 1; }
+
+ //! Simple primitive for parallelization of "for" loops, e.g.:
+ //! @code
+ //! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
+ //! @endcode
+ //! @param theBegin the first data index (inclusive)
+ //! @param theEnd the last data index (exclusive)
+ //! @param theFunctor functor providing an interface
+ //! "void operator(int theThreadIndex, int theDataIndex){}" performing task for specified index
+ template<typename Functor>
+ void Perform (int theBegin, int theEnd, const Functor& theFunctor)
+ {
+ JobRange aData (theBegin, theEnd);
+ Job<Functor> aJob (theFunctor, aData);
+ perform (aJob);
+ }
+
+ //! Release threads before Launcher destruction.
+ Standard_EXPORT void Release();
+
+ protected:
+
+ //! Execute job.
+ Standard_EXPORT void perform (JobInterface& theJob);
+
+ //! Initialize job and start threads.
+ Standard_EXPORT void run (JobInterface& theJob);
+
+ //! Wait threads execution.
+ Standard_EXPORT void wait();
+
+ private:
+ Launcher (const Launcher& theCopy);
+ Launcher& operator=(const Launcher& theCopy);
+
+ private:
+ NCollection_Array1<EnumeratedThread*> myThreads; //!< array of locked threads (including self-thread)
+ EnumeratedThread mySelfThread;
+ int myNbThreads; //!< amount of locked threads
+ };
+
+protected:
+
+ //! Auxiliary class which ensures exclusive access to iterators of processed data pool.
+ class JobRange
+ {
+ public:
+
+ //! Constructor
+ JobRange (const int& theBegin, const int& theEnd) : myBegin(theBegin), myEnd (theEnd), myIt (theBegin) {}
+
+ //! Returns const link on the first element.
+ const int& Begin() const { return myBegin; }
+
+ //! Returns const link on the last element.
+ const int& End() const { return myEnd; }
+
+ //! Returns first non processed element or end.
+ //! Thread-safe method.
+ int It() const { return Standard_Atomic_Increment (reinterpret_cast<volatile int*>(&myIt)) - 1; }
+
+ private:
+ JobRange (const JobRange& theCopy);
+ JobRange& operator=(const JobRange& theCopy);
+
+ private:
+ const int& myBegin; //!< First element of range
+ const int& myEnd; //!< Last element of range
+ mutable int myIt; //!< First non processed element of range
+ };
+
+ //! Auxiliary wrapper class for thread function.
+ template<typename FunctorT> class Job : public JobInterface
+ {
+ public:
+
+ //! Constructor.
+ Job (const FunctorT& thePerformer, JobRange& theRange)
+ : myPerformer (thePerformer), myRange (theRange) {}
+
+ //! Method is executed in the context of thread.
+ virtual void Perform (int theThreadIndex) Standard_OVERRIDE
+ {
+ for (Standard_Integer anIter = myRange.It(); anIter < myRange.End(); anIter = myRange.It())
+ {
+ myPerformer (theThreadIndex, anIter);
+ }
+ }
+
+ private:
+ Job (const Job& theCopy);
+ Job& operator=(const Job& theCopy);
+
+ private: //! @name private fields
+ const FunctorT& myPerformer; //!< Link on functor
+ const JobRange& myRange; //!< Link on processed data block
+ };
+
+ //! Release threads.
+ void release();
+
+ //! Perform the job and catch exceptions.
+ static void performJob (Handle(Standard_Failure)& theFailure,
+ OSD_ThreadPool::JobInterface* theJob,
+ int theThreadIndex);
+
+private:
+
+ NCollection_Array1<EnumeratedThread> myThreads; //!< array of defined threads (excluding self-thread)
+ int myNbDefThreads; //!< maximum number of threads to be locked by a single Launcher by default
+ bool myShutDown; //!< flag to shut down (destroy) the thread pool
+
+};
+
+#endif // _OSD_ThreadPool_HeaderFile
#include <Standard_DivideByZero.hxx>
#include <Standard_Overflow.hxx>
+static Standard_THREADLOCAL Standard_Boolean fFltExceptions = Standard_False;
+
+//=======================================================================
+//function : ToCatchFloatingSignals
+//purpose :
+//=======================================================================
+Standard_Boolean OSD::ToCatchFloatingSignals()
+{
+ return fFltExceptions;
+}
+
#ifdef _WIN32
//---------------------------- Windows NT System --------------------------------
#include <Standard_ProgramError.hxx>
#include <Standard_Mutex.hxx>
-#include <OSD_WNT_1.hxx>
+#include <OSD_WNT.hxx>
#ifdef _MSC_VER
#include <eh.h>
#include <float.h>
static Standard_Boolean fCtrlBrk;
-#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
+
static Standard_Boolean fMsgBox;
-static Standard_Boolean fFltExceptions;
-static Standard_Boolean fDbgLoaded;
// used to forbid simultaneous execution of setting / executing handlers
static Standard_Mutex THE_SIGNAL_MUTEX;
static LONG __fastcall _osd_raise ( DWORD, LPSTR );
static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
-#ifndef OCCT_UWP
+#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
+static Standard_Boolean fDbgLoaded;
static LONG _osd_debug ( void );
#endif
//# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
+#ifdef OCC_CONVERT_SIGNALS
+#define THROW_OR_JUMP(Type,Message) Type::NewInstance(Message)->Jump()
+#else
+#define THROW_OR_JUMP(Type,Message) throw Type(Message)
+#endif
+
//=======================================================================
//function : CallHandler
//purpose :
break ;
case STATUS_NO_MEMORY:
// cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
- throw OSD_Exception_STATUS_NO_MEMORY ( "MEMORY ALLOCATION ERROR ( no room in the process heap )" );
+ THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )");
+ break;
case EXCEPTION_ACCESS_VIOLATION:
// cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
_fpreset();
_clearfp();
-#ifndef OCCT_UWP
+#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
MessageBeep ( MB_ICONHAND );
int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
if (aChoice == IDRETRY)
break ;
default:
cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << endl;
- throw Standard_NumericError("Floating Point Error");
+ THROW_OR_JUMP (Standard_NumericError, "Floating Point Error");
break ;
}
break ;
DebugBreak ();
#endif
}
-#endif
//=======================================================================
//function : TranslateSE
// option and unless user sets his own exception handler with
// ::SetUnhandledExceptionFilter().
//=======================================================================
-#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
{
DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
lpXP->ExceptionRecord->ExceptionInformation[1],
lpXP->ExceptionRecord->ExceptionInformation[0]);
}
-#endif
//=======================================================================
//function : SetSignal
//=======================================================================
void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
{
-#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
#if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
- LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
-
OSD_Environment env ("CSF_DEBUG_MODE");
TCollection_AsciiString val = env.Value();
if (!env.Failed())
// when user's code is compiled with /EHs
// Replaces the existing top-level exception filter for all existing and all future threads
// in the calling process
- aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
+ ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
#endif // NTDDI_WIN10_TH2
// Signal handlers will only be used when the method ::raise() will be used
else {
_controlfp (_OSD_FPX, _OSD_FPX); // JR add :
}
-#endif
} // end OSD :: SetSignal
//============================================================================
throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
}
} // end OSD :: ControlBreak
-#if !defined(__MINGW32__) && !defined(__CYGWIN32__)
+
#ifndef OCCT_UWP
//============================================================================
//==== _osd_ctrl_break_handler
return TRUE;
} // end _osd_ctrl_break_handler
#endif
+
//============================================================================
//==== _osd_raise
//============================================================================
switch (dwCode)
{
case EXCEPTION_ACCESS_VIOLATION:
- throw OSD_Exception_ACCESS_VIOLATION(msg);
+ THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, msg);
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- throw OSD_Exception_ARRAY_BOUNDS_EXCEEDED(msg);
+ THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, msg);
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
- throw Standard_ProgramError(msg);
+ THROW_OR_JUMP (Standard_ProgramError, msg);
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
- throw OSD_Exception_ILLEGAL_INSTRUCTION(msg);
+ THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, msg);
break;
case EXCEPTION_IN_PAGE_ERROR:
- throw OSD_Exception_IN_PAGE_ERROR(msg);
+ THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, msg);
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
- throw Standard_DivideByZero(msg);
+ THROW_OR_JUMP (Standard_DivideByZero, msg);
break;
case EXCEPTION_INT_OVERFLOW:
- throw OSD_Exception_INT_OVERFLOW(msg);
+ THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, msg);
break;
case EXCEPTION_INVALID_DISPOSITION:
- throw OSD_Exception_INVALID_DISPOSITION(msg);
+ THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, msg);
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- throw OSD_Exception_NONCONTINUABLE_EXCEPTION(msg);
+ THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, msg);
break;
case EXCEPTION_PRIV_INSTRUCTION:
- throw OSD_Exception_PRIV_INSTRUCTION(msg);
+ THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, msg);
break;
case EXCEPTION_STACK_OVERFLOW:
- throw OSD_Exception_STACK_OVERFLOW(msg);
+ THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, msg);
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- throw Standard_DivideByZero(msg);
+ THROW_OR_JUMP (Standard_DivideByZero, msg);
break;
case EXCEPTION_FLT_STACK_CHECK:
case EXCEPTION_FLT_OVERFLOW:
- throw Standard_Overflow(msg);
+ THROW_OR_JUMP (Standard_Overflow, msg);
break;
case EXCEPTION_FLT_UNDERFLOW:
- throw Standard_Underflow(msg);
+ THROW_OR_JUMP (Standard_Underflow, msg);
break;
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_INEXACT_RESULT:
case STATUS_FLOAT_MULTIPLE_TRAPS:
case STATUS_FLOAT_MULTIPLE_FAULTS:
- throw Standard_NumericError(msg);
+ THROW_OR_JUMP (Standard_NumericError, msg);
break;
default:
break;
return EXCEPTION_EXECUTE_HANDLER;
} // end _osd_raise
+#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
//============================================================================
//==== _osd_debug
//============================================================================
-#ifndef OCCT_UWP
LONG _osd_debug ( void ) {
LONG action ;
return action ;
} // end _osd_debug
+#endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
-#endif
-#endif
-#else
+#else /* ! _WIN32 */
//---------- All Systems except Windows NT : ----------------------------------
#ifdef __linux__
#include <cfenv>
//#include <fenv.h>
-static Standard_Boolean fFltExceptions = Standard_False;
#endif
// variable signalling that Control-C has been pressed (SIGINT signal)
# include <stdlib.h>
# include <stdio.h>
#else
-# ifdef SA_SIGINFO
+# ifdef SA_SIGINFO
# ifndef _AIX
# include <sys/siginfo.h>
# endif
#endif
//============================================================================
-//==== SetSignal
+//==== SetSignal
//==== Set the differents signals:
//============================================================================
-void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
+void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
{
struct sigaction act, oact;
int stat = 0;
#endif
//==== Always detected the signal "SIGFPE" =================================
- stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
+ stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
if (stat) {
#ifdef OCCT_DEBUG
cerr << "sigaction does not work !!! KO " << endl;
}
//==== Detected the only the "free" signals ================================
- sigaction(SIGHUP,&act,&oact); // ...... hangup
+ sigaction(SIGHUP,&act,&oact); // ...... hangup
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGHUP,&oact,&oact);
#endif
- sigaction(SIGINT,&act,&oact); // ...... interrupt
+ sigaction(SIGINT,&act,&oact); // ...... interrupt
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGINT,&oact,&oact);
#endif
-
+
sigaction(SIGQUIT,&act,&oact); // ...... quit
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGQUIT,&oact,&oact);
#endif
- sigaction(SIGILL,&act,&oact); // ...... illegal instruction
+ sigaction(SIGILL,&act,&oact); // ...... illegal instruction
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGILL,&oact,&oact);
#endif
- sigaction(SIGBUS,&act,&oact); // ...... bus error
+ sigaction(SIGBUS,&act,&oact); // ...... bus error
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGBUS,&oact,&oact);
#endif
sigaction(SIGSYS,&act,&oact); // ...... bad argument to system call
# ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGSYS,&oact,&oact);
# endif
#endif
sigaction(SIGTRAP,&act,&oact); // Integer Divide By Zero (IRIX)
# ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGTRAP,&oact,&oact);
# endif
#endif
perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
#ifdef OBJS
- if(oact.sa_handler)
+ if(oact.sa_handler)
sigaction(SIGSEGV,&oact,&oact);
#endif
#if defined(__osf__) || defined(DECOSF1)
action.sa_handler = SIG_IGN;
action.sa_mask = 0;
action.sa_flags = 0;
-
+
if (sigaction (SIGFPE, &action, &prev_action) == -1) {
perror ("sigaction");
exit (1);
}
//============================================================================
-//==== ControlBreak
+//==== ControlBreak
//============================================================================
-void OSD :: ControlBreak ()
+void OSD :: ControlBreak ()
{
if ( fCtrlBrk ) {
fCtrlBrk = Standard_False;
- throw OSD_Exception_CTRL_BREAK("*** INTERRUPT ***");
+ throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");
}
}
Standard_Character.hxx
Standard_CLocaleSentry.cxx
Standard_CLocaleSentry.hxx
+Standard_Condition.cxx
+Standard_Condition.hxx
Standard_ConstructionError.hxx
Standard_Copy.tcl
Standard_CString.cxx
Standard_ShortReal.cxx
Standard_ShortReal.hxx
Standard_Size.hxx
-Standard_SStream.cxx
Standard_SStream.hxx
Standard_Stream.hxx
+Standard_Strtod.cxx
Standard_ThreadId.hxx
Standard_Time.hxx
Standard_TooManyUsers.hxx
Standard_TypeDef.hxx
Standard_TypeMismatch.hxx
Standard_Underflow.hxx
-Standard_UUID.cxx
Standard_UUID.hxx
Standard_values.h
Standard_Version.hxx
+Standard_WarningsDisable.hxx
+Standard_WarningsRestore.hxx
\ No newline at end of file
//! and returns resulting decremented value.
inline int Standard_Atomic_Decrement (volatile int* theValue);
+//! Perform an atomic compare and swap.
+//! That is, if the current value of *theValue is theOldValue, then write theNewValue into *theValue.
+//! @param theValue pointer to variable to modify
+//! @param theOldValue expected value to perform modification
+//! @param theNewValue new value to set in case if *theValue was equal to theOldValue
+//! @return TRUE if theNewValue has been set to *theValue
+inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
+
// Platform-dependent implementation
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
return __sync_sub_and_fetch (theValue, 1);
}
+bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
+{
+ return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue;
+}
+
#elif defined(_WIN32)
extern "C" {
long _InterlockedIncrement (volatile long* lpAddend);
long _InterlockedDecrement (volatile long* lpAddend);
+ long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand);
}
-#if defined(_MSC_VER)
+#if defined(_MSC_VER) && ! defined(__INTEL_COMPILER)
// force intrinsic instead of WinAPI calls
#pragma intrinsic (_InterlockedIncrement)
#pragma intrinsic (_InterlockedDecrement)
+ #pragma intrinsic (_InterlockedCompareExchange)
#endif
// WinAPI function or MSVC intrinsic
return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
}
+bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
+{
+ return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue;
+}
+
#elif defined(__APPLE__)
// use atomic operations provided by MacOS
return OSAtomicDecrement32Barrier (theValue);
}
+bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
+{
+ return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue);
+}
+
#elif defined(__ANDROID__)
// Atomic operations that were exported by the C library didn't
return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
}
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
-// use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
-
-inline int Standard_Atomic_Add (volatile int* theValue, int theVal)
+bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
{
- // C equivalent:
- // *theValue += theVal;
- // return *theValue;
-
- int previous;
- __asm__ __volatile__
- (
- "lock xadd %0,%1"
- : "=q"(previous), "=m"(*theValue) //output
- : "0"(theVal), "m"(*theValue) //input
- : "memory" //clobbers
- );
- return previous + theVal;
-}
-
-int Standard_Atomic_Increment (volatile int* theValue)
-{
- return Standard_Atomic_Add (theValue, 1);
-}
-
-int Standard_Atomic_Decrement (volatile int* theValue)
-{
- return Standard_Atomic_Add (theValue, -1);
+ return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0;
}
#else
return --(*theValue);
}
+bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
+{
+ if (*theValue == theOldValue)
+ {
+ *theValue = theNewValue;
+ return true;
+ }
+ return false;
+}
+
#endif
#endif //_Standard_Atomic_HeaderFile
--- /dev/null
+// Created by: Kirill Gavrilov
+// Copyright (c) 2018 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifdef _WIN32
+ #include <windows.h>
+#else
+ #include <pthread.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <sys/time.h>
+#endif
+
+#include "Standard_Condition.hxx"
+
+namespace
+{
+#ifndef _WIN32
+ //! clock_gettime() wrapper.
+ static void conditionGetRealTime (struct timespec& theTime)
+ {
+ #if defined(__APPLE__)
+ struct timeval aTime;
+ gettimeofday (&aTime, NULL);
+ theTime.tv_sec = aTime.tv_sec;
+ theTime.tv_nsec = aTime.tv_usec * 1000;
+ #else
+ clock_gettime (CLOCK_REALTIME, &theTime);
+ #endif
+ }
+#endif
+}
+
+// =======================================================================
+// function : Standard_Condition
+// purpose :
+// =======================================================================
+Standard_Condition::Standard_Condition (bool theIsSet)
+#ifdef _WIN32
+: myEvent((void* )::CreateEvent (0, true, theIsSet, NULL))
+#else
+: myFlag (theIsSet)
+#endif
+{
+#ifndef _WIN32
+ pthread_mutex_init(&myMutex, 0);
+ pthread_cond_init (&myCond, 0);
+#endif
+}
+
+// =======================================================================
+// function : ~Standard_Condition
+// purpose :
+// =======================================================================
+Standard_Condition::~Standard_Condition()
+{
+#ifdef _WIN32
+ ::CloseHandle ((HANDLE )myEvent);
+#else
+ pthread_mutex_destroy(&myMutex);
+ pthread_cond_destroy (&myCond);
+#endif
+}
+
+// =======================================================================
+// function : Set
+// purpose :
+// =======================================================================
+void Standard_Condition::Set()
+{
+#ifdef _WIN32
+ ::SetEvent ((HANDLE )myEvent);
+#else
+ pthread_mutex_lock(&myMutex);
+ myFlag = true;
+ pthread_cond_broadcast(&myCond);
+ pthread_mutex_unlock (&myMutex);
+#endif
+}
+
+// =======================================================================
+// function : Reset
+// purpose :
+// =======================================================================
+void Standard_Condition::Reset()
+{
+#ifdef _WIN32
+ ::ResetEvent ((HANDLE )myEvent);
+#else
+ pthread_mutex_lock (&myMutex);
+ myFlag = false;
+ pthread_mutex_unlock (&myMutex);
+#endif
+}
+
+// =======================================================================
+// function : Wait
+// purpose :
+// =======================================================================
+void Standard_Condition::Wait()
+{
+#ifdef _WIN32
+ ::WaitForSingleObject ((HANDLE )myEvent, INFINITE);
+#else
+ pthread_mutex_lock (&myMutex);
+ if (!myFlag)
+ {
+ pthread_cond_wait (&myCond, &myMutex);
+ }
+ pthread_mutex_unlock (&myMutex);
+#endif
+}
+
+// =======================================================================
+// function : Wait
+// purpose :
+// =======================================================================
+bool Standard_Condition::Wait (int theTimeMilliseconds)
+{
+#ifdef _WIN32
+ return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )theTimeMilliseconds) != WAIT_TIMEOUT);
+#else
+ bool isSignalled = true;
+ pthread_mutex_lock (&myMutex);
+ if (!myFlag)
+ {
+ struct timespec aNow;
+ struct timespec aTimeout;
+ conditionGetRealTime (aNow);
+ aTimeout.tv_sec = (theTimeMilliseconds / 1000);
+ aTimeout.tv_nsec = (theTimeMilliseconds - aTimeout.tv_sec * 1000) * 1000000;
+ if (aTimeout.tv_nsec > 1000000000)
+ {
+ aTimeout.tv_sec += 1;
+ aTimeout.tv_nsec -= 1000000000;
+ }
+ aTimeout.tv_sec += aNow.tv_sec;
+ aTimeout.tv_nsec += aNow.tv_nsec;
+ isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
+ }
+ pthread_mutex_unlock (&myMutex);
+ return isSignalled;
+#endif
+}
+
+// =======================================================================
+// function : Check
+// purpose :
+// =======================================================================
+bool Standard_Condition::Check()
+{
+#ifdef _WIN32
+ return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
+#else
+ bool isSignalled = true;
+ pthread_mutex_lock (&myMutex);
+ if (!myFlag)
+ {
+ struct timespec aNow;
+ struct timespec aTimeout;
+ conditionGetRealTime (aNow);
+ aTimeout.tv_sec = aNow.tv_sec;
+ aTimeout.tv_nsec = aNow.tv_nsec + 100;
+ isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
+ }
+ pthread_mutex_unlock (&myMutex);
+ return isSignalled;
+#endif
+}
+
+// =======================================================================
+// function : CheckReset
+// purpose :
+// =======================================================================
+bool Standard_Condition::CheckReset()
+{
+#ifdef _WIN32
+ const bool wasSignalled = (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
+ ::ResetEvent ((HANDLE )myEvent);
+ return wasSignalled;
+#else
+ pthread_mutex_lock (&myMutex);
+ bool wasSignalled = myFlag;
+ if (!myFlag)
+ {
+ struct timespec aNow;
+ struct timespec aTimeout;
+ conditionGetRealTime (aNow);
+ aTimeout.tv_sec = aNow.tv_sec;
+ aTimeout.tv_nsec = aNow.tv_nsec + 100;
+ wasSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
+ }
+ myFlag = false;
+ pthread_mutex_unlock (&myMutex);
+ return wasSignalled;
+#endif
+}
--- /dev/null
+// Created by: Kirill Gavrilov
+// Copyright (c) 2018 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Standard_Condition_HeaderFile
+#define _Standard_Condition_HeaderFile
+
+#include <Standard.hxx>
+
+#ifndef _WIN32
+ #include <pthread.h>
+#endif
+
+//! This is boolean flag intended for communication between threads.
+//! One thread sets this flag to TRUE to indicate some event happened
+//! and another thread either waits this event or checks periodically its state to perform job.
+//!
+//! This class provides interface similar to WinAPI Event objects.
+class Standard_Condition
+{
+public:
+
+ //! Default constructor.
+ //! @param theIsSet Initial flag state
+ Standard_EXPORT Standard_Condition (bool theIsSet);
+
+ //! Destructor.
+ Standard_EXPORT ~Standard_Condition();
+
+ //! Set event into signaling state.
+ Standard_EXPORT void Set();
+
+ //! Reset event (unset signaling state)
+ Standard_EXPORT void Reset();
+
+ //! Wait for Event (infinity).
+ Standard_EXPORT void Wait();
+
+ //! Wait for signal requested time.
+ //! @param theTimeMilliseconds wait limit in milliseconds
+ //! @return true if get event
+ Standard_EXPORT bool Wait (int theTimeMilliseconds);
+
+ //! Do not wait for signal - just test it state.
+ //! @return true if get event
+ Standard_EXPORT bool Check();
+
+ //! Method perform two steps at-once - reset the event object
+ //! and returns true if it was in signaling state.
+ //! @return true if event object was in signaling state.
+ Standard_EXPORT bool CheckReset();
+
+#ifdef _WIN32
+ //! Access native HANDLE to Event object.
+ void* getHandle() const { return myEvent; }
+#endif
+
+private:
+
+#ifdef _WIN32
+ void* myEvent;
+#else
+ pthread_mutex_t myMutex;
+ pthread_cond_t myCond;
+ bool myFlag;
+#endif
+
+};
+
+#endif // _Standard_Condition_HeaderFile
}
}
-// Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
-#if defined(__clang__)
- // CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
- // Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
- #if __has_feature(cxx_thread_local)
- #define Standard_THREADLOCAL thread_local
- #else
- #define Standard_THREADLOCAL
- #endif
-#elif (defined(__INTEL_COMPILER) && __INTEL_COMPILER > 1400) || \
- (defined(_MSC_VER) && _MSC_VER >= 1900) /* MSVC++ >= 14 */ || \
- (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) /* GCC >= 4.8 */
- #define Standard_THREADLOCAL thread_local
-#else
- #define Standard_THREADLOCAL
-#endif
-
// ******************************************************************
// Standard_Failure *
// ******************************************************************
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-// Purpose: This file is intended to be the first file #included to any
-// Open CASCADE source. It defines platform-specific pre-processor
-// macros necessary for correct compilation of Open CASCADE code
+//! @file
+//! This file is intended to be the first file included to any
+//! Open CASCADE source. It defines platform-specific pre-processor
+//! macros necessary for correct compilation of Open CASCADE code.
#ifndef _Standard_Macro_HeaderFile
# define _Standard_Macro_HeaderFile
+//! @def Standard_OVERRIDE
+//! Should be used in declarations of virtual methods overriden in the
+//! derived classes, to cause compilation error in the case if that virtual
+//! function disappears or changes its signature in the base class.
+//!
+//! Expands to C++11 keyword "override" on compilers that are known to
+//! suppot it; empty in other cases.
#if defined(__cplusplus) && (__cplusplus >= 201100L)
// part of C++11 standard
#define Standard_OVERRIDE override
#define Standard_OVERRIDE
#endif
-// Macro for marking variables / functions as possibly unused
-// so that compiler will not emit redundant "unused" warnings.
+//! @def Standard_FALLTHROUGH
+//! Should be used in a switch statement immediately before a case label,
+//! if code associated with the previous case label may fall through to that
+//! next label (i.e. does not end with "break" or "return" etc.).
+//! This macro indicates that the fall through is intentional and should not be
+//! diagnosed by a compiler that warns on fallthrough.
+//!
+//! Expands to C++17 attribute statement "[[fallthrough]];" on compilers that
+//! declare support of C++17, or to "__attribute__((fallthrough));" on
+//! GCC 7+.
+#if defined(__cplusplus) && (__cplusplus >= 201703L)
+ // part of C++17 standard
+ #define Standard_FALLTHROUGH [[fallthrough]];
+#elif defined(__GNUC__) && (__GNUC__ >= 7)
+ // gcc 7+
+ #define Standard_FALLTHROUGH __attribute__((fallthrough));
+#else
+ #define Standard_FALLTHROUGH
+#endif
+
+//! @def Standard_UNUSED
+//! Macro for marking variables / functions as possibly unused
+//! so that compiler will not emit redundant "unused" warnings.
+//!
+//! Expands to "__attribute__((unused))" on GCC and CLang.
#if defined(__GNUC__) || defined(__clang__)
#define Standard_UNUSED __attribute__((unused))
#else
#define Standard_UNUSED
#endif
-// Macro Standard_DEPRECATED("message") can be used to declare a method deprecated.
-// If OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
+//! @def Standard_THREADLOCAL
+//! Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
+#if defined(__clang__)
+ // CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
+ // Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
+ #if __has_feature(cxx_thread_local)
+ #define Standard_THREADLOCAL thread_local
+ #endif
+#elif defined(__INTEL_COMPILER)
+ #if (defined(_MSC_VER) && _MSC_VER >= 1900 && __INTEL_COMPILER > 1400)
+ // requires msvcrt vc14+ (Visual Studio 2015+)
+ #define Standard_THREADLOCAL thread_local
+ #elif (!defined(_MSC_VER) && __INTEL_COMPILER > 1500)
+ #define Standard_THREADLOCAL thread_local
+ #endif
+#elif (defined(_MSC_VER) && _MSC_VER >= 1900)
+ // msvcrt coming with vc14+ (VS2015+)
+ #define Standard_THREADLOCAL thread_local
+#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
+ // GCC >= 4.8
+ #define Standard_THREADLOCAL thread_local
+#endif
+
+#ifndef Standard_THREADLOCAL
+ #define Standard_THREADLOCAL
+#endif
+
+//! @def Standard_DEPRECATED("message")
+//! Can be used in declaration of a method or a class to mark it as deprecated.
+//! Use of such method or class will cause compiler warning (if supported by
+//! compiler and unless disabled).
+//! If macro OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
#ifdef OCCT_NO_DEPRECATED
#define Standard_DEPRECATED(theMsg)
#else
#endif
#endif
-// Disable warnings about deprecated features.
-// This is useful for sections of code kept for backward compatibility and scheduled for removal.
-
+//! @def Standard_DISABLE_DEPRECATION_WARNINGS
+//! Disables warnings on use of deprecated features (see Standard_DEPRECATED),
+//! from the current point till appearance of Standard_ENABLE_DEPRECATION_WARNINGS macro.
+//! This is useful for sections of code kept for backward compatibility and scheduled for removal.
+//!
+//! @def Standard_ENABLE_DEPRECATION_WARNINGS
+//! Enables warnings on use of deprecated features previously disabled by
+//! Standard_DISABLE_DEPRECATION_WARNINGS.
#if defined(__ICL) || defined (__INTEL_COMPILER)
#define Standard_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478))
#define Standard_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
#define Standard_ENABLE_DEPRECATION_WARNINGS
#endif
+//! @def OCCT_NO_RVALUE_REFERENCE
+//! Disables methods and constructors that use rvalue references
+//! (C++11 move semantics) not supported by obsolete compilers.
+#if (defined(_MSC_VER) && (_MSC_VER < 1600))
+ #define OCCT_NO_RVALUE_REFERENCE
+#endif
+
# ifdef _WIN32
// We must be careful including windows.h: it is really poisonous stuff!
#endif
-# if defined(_WIN32) && !defined(HAVE_NO_DLL)
+//! @def Standard_EXPORT
+//! This macro should be used in declarations of public methods
+//! to ensure that they are exported from DLL on Windows and thus
+//! can be called from other (dependent) libraries or applications.
+//!
+//! If macro OCCT_STATIC_BUILD is defined, then Standard_EXPORT
+//! is set to empty.
+
+# if defined(_WIN32) && !defined(OCCT_STATIC_BUILD) && !defined(HAVE_NO_DLL)
//======================================================
// Windows-specific definitions
# endif /* _WIN32 */
-//======================================================
-// Other
-//======================================================
-
-# ifndef __Standard_API
-# if !defined(_WIN32) || defined(__Standard_DLL) || defined(__FSD_DLL) || defined(__MMgt_DLL) || defined(__OSD_DLL) || defined(__Plugin_DLL) || defined(__Quantity_DLL) || defined(__Resource_DLL) || defined(__SortTools_DLL) || defined(__StdFail_DLL) || defined(__Storage_DLL) || defined(__TColStd_DLL) || defined(__TCollection_DLL) || defined(__TShort_DLL) || defined(__Units_DLL) || defined(__UnitsAPI_DLL) || defined(__Dico_DLL)
-# define __Standard_API Standard_EXPORT
-# define __Standard_APIEXTERN Standard_EXPORTEXTERN
-# else
-# define __Standard_API Standard_IMPORT
-# define __Standard_APIEXTERN Standard_IMPORT
-# endif // __Standard_DLL
-# endif // __Standard_API
-
-// Support of Universal Windows Platform
+//! @def OCCT_UWP
+//! This macro is defined on Windows platform in the case if the code
+//! is being compiled for UWP (Universal Windows Platform).
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP
#define OCCT_UWP
#else