]> OCCT Git - occt-copy.git/commitdiff
0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool CR0_v720_FIXhm
authornbv <nbv@opencascade.com>
Wed, 20 Feb 2019 13:52:22 +0000 (16:52 +0300)
committernbv <nbv@opencascade.com>
Wed, 20 Feb 2019 14:03:08 +0000 (17:03 +0300)
16 files changed:
src/BRepMesh/BRepMesh_FastDiscret.cxx
src/BRepMesh/BRepMesh_IncrementalMesh.cxx
src/OSD/FILES
src/OSD/OSD.hxx
src/OSD/OSD_Parallel.hxx
src/OSD/OSD_Parallel_TBB.cxx [new file with mode: 0644]
src/OSD/OSD_Parallel_Threads.cxx [new file with mode: 0644]
src/OSD/OSD_ThreadPool.cxx [new file with mode: 0644]
src/OSD/OSD_ThreadPool.hxx [new file with mode: 0644]
src/OSD/OSD_signal.cxx
src/Standard/FILES
src/Standard/Standard_Atomic.hxx
src/Standard/Standard_Condition.cxx [new file with mode: 0644]
src/Standard/Standard_Condition.hxx [new file with mode: 0644]
src/Standard/Standard_Failure.cxx
src/Standard/Standard_Macro.hxx

index 1d453897ff34488535ab856926a24707482749f5..56e7b5f7112cda704971c0f73b9557ec3d83f7fc 100644 (file)
@@ -120,7 +120,7 @@ void BRepMesh_FastDiscret::Perform(const TopoDS_Shape& theShape)
     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());
 }
 
 
index 70278be25991cf217e1b4228a58e00ca659e00c2..09bd970a610c39207549a881813394709bf8d80a 100644 (file)
@@ -234,7 +234,7 @@ void BRepMesh_IncrementalMesh::update()
     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();
index c9e53811a0bf5f5378ed54f4ba181b4928a2fac9..2c33e882b97eca022551ccbdc12e0994521bfbff 100755 (executable)
@@ -57,6 +57,8 @@ OSD_OpenMode.hxx
 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
@@ -83,6 +85,8 @@ OSD_SingleProtection.hxx
 OSD_SysType.hxx
 OSD_Thread.cxx
 OSD_Thread.hxx
+OSD_ThreadPool.cxx
+OSD_ThreadPool.hxx
 OSD_ThreadFunction.hxx
 OSD_Timer.cxx
 OSD_Timer.hxx
index 4418a1176687ea6da7b62a653ccac0fcec3996d4..dd80e028b0833e9f735c19d0e58a3da3a5d81f9e 100644 (file)
@@ -104,7 +104,10 @@ public:
   //! 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);
   
index 3f34408b7459900b1a6410ce89ed346a135dc825..d39e9d7b47564521582caf049956cac403cb80dd 100644 (file)
 #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
diff --git a/src/OSD/OSD_Parallel_TBB.cxx b/src/OSD/OSD_Parallel_TBB.cxx
new file mode 100644 (file)
index 0000000..508119f
--- /dev/null
@@ -0,0 +1,48 @@
+// 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
diff --git a/src/OSD/OSD_Parallel_Threads.cxx b/src/OSD/OSD_Parallel_Threads.cxx
new file mode 100644 (file)
index 0000000..0ffb38f
--- /dev/null
@@ -0,0 +1,159 @@
+// 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 */
diff --git a/src/OSD/OSD_ThreadPool.cxx b/src/OSD/OSD_ThreadPool.cxx
new file mode 100644 (file)
index 0000000..70ad50b
--- /dev/null
@@ -0,0 +1,401 @@
+// 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;
+}
diff --git a/src/OSD/OSD_ThreadPool.hxx b/src/OSD/OSD_ThreadPool.hxx
new file mode 100644 (file)
index 0000000..8b6dab6
--- /dev/null
@@ -0,0 +1,301 @@
+// 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
index 10a9c425ab4b10c04e2f8ee8db3bb95e170de54a..06b6394039847b1bbc5c8927c61acc3b84070877 100644 (file)
 #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 --------------------------------
 
@@ -53,7 +64,7 @@
 #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;
@@ -76,13 +85,20 @@ 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  :
@@ -148,7 +164,8 @@ static LONG CallHandler (DWORD dwExceptionCode,
       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",
@@ -227,7 +244,7 @@ static LONG CallHandler (DWORD dwExceptionCode,
     _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)
@@ -287,7 +304,7 @@ static void SIGWntHandler (int signum, int sub_code)
           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 ;
@@ -309,7 +326,6 @@ static void SIGWntHandler (int signum, int sub_code)
   DebugBreak ();
 #endif
 }
-#endif
 
 //=======================================================================
 //function : TranslateSE
@@ -342,7 +358,6 @@ static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
 //           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;
@@ -351,7 +366,6 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
                       lpXP->ExceptionRecord->ExceptionInformation[1],
                       lpXP->ExceptionRecord->ExceptionInformation[0]);
 }
-#endif
 
 //=======================================================================
 //function : SetSignal
@@ -359,11 +373,8 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
 //=======================================================================
 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())
@@ -380,7 +391,7 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
   // 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
@@ -410,7 +421,6 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
   else {
     _controlfp (_OSD_FPX, _OSD_FPX); // JR add :
   }
-#endif
 }  // end OSD :: SetSignal
 
 //============================================================================
@@ -422,7 +432,7 @@ void OSD::ControlBreak () {
     throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
   }
 }  // end OSD :: ControlBreak
-#if !defined(__MINGW32__) && !defined(__CYGWIN32__)
+
 #ifndef OCCT_UWP
 //============================================================================
 //==== _osd_ctrl_break_handler
@@ -437,6 +447,7 @@ static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
   return TRUE;
 }  // end _osd_ctrl_break_handler
 #endif
+
 //============================================================================
 //==== _osd_raise
 //============================================================================
@@ -447,54 +458,54 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
   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;
@@ -502,10 +513,10 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
   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 ;
@@ -588,10 +599,9 @@ LONG _osd_debug ( void ) {
   return action ;
 
 }  // end _osd_debug
+#endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
 
-#endif
-#endif
-#else
+#else /* ! _WIN32 */
 
 //---------- All Systems except Windows NT : ----------------------------------
 
@@ -616,7 +626,6 @@ LONG _osd_debug ( void ) {
 #ifdef __linux__
 #include  <cfenv>
 //#include  <fenv.h>
-static Standard_Boolean fFltExceptions = Standard_False;
 #endif
 
 // variable signalling that Control-C has been pressed (SIGINT signal)
@@ -635,7 +644,7 @@ typedef void (* SIG_PFV) (int);
 # include <stdlib.h>
 # include <stdio.h>
 #else
-#  ifdef SA_SIGINFO 
+#  ifdef SA_SIGINFO
 #    ifndef _AIX
 #  include <sys/siginfo.h>
 #     endif
@@ -866,11 +875,11 @@ static void SegvHandler(const int theSignal,
 #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;
@@ -932,7 +941,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
 #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;
@@ -941,38 +950,38 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
   }
 
   //==== 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
 
@@ -980,7 +989,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
   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
@@ -989,7 +998,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
   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
@@ -1004,7 +1013,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
     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)
@@ -1012,7 +1021,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
    action.sa_handler = SIG_IGN;
    action.sa_mask = 0;
    action.sa_flags = 0;
-   
+
    if (sigaction (SIGFPE, &action, &prev_action) == -1) {
      perror ("sigaction");
      exit (1);
@@ -1022,14 +1031,14 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
 }
 
 //============================================================================
-//==== 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 ***");
   }
 }
 
index da33f5a0e9408c7934543ddc6bde45d371d381ef..1d752bb89f603422dcabb616b6b41f7faf163e79 100755 (executable)
@@ -11,6 +11,8 @@ Standard_Byte.hxx
 Standard_Character.hxx
 Standard_CLocaleSentry.cxx
 Standard_CLocaleSentry.hxx
+Standard_Condition.cxx
+Standard_Condition.hxx
 Standard_ConstructionError.hxx
 Standard_Copy.tcl
 Standard_CString.cxx
@@ -79,9 +81,9 @@ Standard_Real.hxx
 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
@@ -92,7 +94,8 @@ Standard_Type.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
index a5b5944031d05ee11e19aed5f348e8b038404920..678e211dc225a356c3dd8d5c3f30a874a89ac142 100644 (file)
@@ -35,6 +35,14 @@ inline int Standard_Atomic_Increment (volatile int* theValue);
 //! 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_*
@@ -55,16 +63,23 @@ int Standard_Atomic_Decrement (volatile int* theValue)
   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
@@ -80,6 +95,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
   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
 
@@ -95,6 +115,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
   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
@@ -114,34 +139,9 @@ int Standard_Atomic_Decrement (volatile int* theValue)
   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
@@ -159,6 +159,16 @@ int Standard_Atomic_Decrement (volatile int* theValue)
   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
diff --git a/src/Standard/Standard_Condition.cxx b/src/Standard/Standard_Condition.cxx
new file mode 100644 (file)
index 0000000..232ae2b
--- /dev/null
@@ -0,0 +1,207 @@
+// 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
+}
diff --git a/src/Standard/Standard_Condition.hxx b/src/Standard/Standard_Condition.hxx
new file mode 100644 (file)
index 0000000..c2f33dc
--- /dev/null
@@ -0,0 +1,80 @@
+// 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
index b7a4d147b61f21fb53f7a8db56bff2d3a0a7a6f0..b0b15409984c8e5440e7bfb54e5931d4e0cda155 100644 (file)
@@ -58,23 +58,6 @@ static void deallocate_message(Standard_CString aMessage)
   }
 }
 
-// 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                       *
 // ******************************************************************
index fd04320593a2bd65f3a8b187aba5b77eea1d96bb..ebcd0f329e2ddccdb8a5625eed7fa9e0ae994372 100644 (file)
 // 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