0028657: Foundation Classes - OSD_Thread does not release thread resources on non...
authorkgv <kgv@opencascade.com>
Sat, 15 Apr 2017 15:57:30 +0000 (18:57 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 20 Apr 2017 09:36:01 +0000 (12:36 +0300)
~OSD_Thread(), OSD_Thread::SetFunction() and OSD_Thread::Run()
now detach old thread also on platforms using pthreads.
OSD_Thread::Wait() now closes thread handle after joining.

src/OSD/OSD_Thread.cxx
src/OSD/OSD_Thread.hxx

index 9509768..6cb9716 100644 (file)
@@ -13,7 +13,6 @@
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-
 #include <OSD_Thread.hxx>
 
 //=============================================
@@ -47,54 +46,35 @@ OSD_Thread::OSD_Thread (const OSD_Thread &other)
 
 void OSD_Thread::Assign (const OSD_Thread &other)
 {
-  // copy function pointer 
+  // copy function pointer
   myFunc = other.myFunc;
   myPriority = other.myPriority;
 
-#ifdef _WIN32
-
-  // On Windows, close current handle 
-  if ( myThread ) 
-    CloseHandle ( myThread );
-  myThread = 0;
+  // detach current thread
+  Detach();
 
-  // and replace it by duplicate of the source handle 
+#ifdef _WIN32
+  // duplicate the source handle
   if ( other.myThread ) {
     HANDLE hProc = GetCurrentProcess(); // we are always within the same process
     DuplicateHandle ( hProc, other.myThread, hProc, &myThread,
                      0, TRUE, DUPLICATE_SAME_ACCESS );
   }
-
 #else
-
   // On Unix/Linux, just copy the thread id
   myThread = other.myThread;
-
-#endif  
+#endif
 
   myThreadId = other.myThreadId;
 }
 
 //=============================================
-// OSD_Thread::Destroy
+// OSD_Thread::~OSD_Thread
 //=============================================
 
-void OSD_Thread::Destroy ()
+OSD_Thread::~OSD_Thread()
 {
-#ifdef _WIN32
-
-  // On Windows, close current handle 
-  if ( myThread ) 
-    CloseHandle ( myThread );
-
-#else
-
-  // On Unix/Linux, do nothing
-
-#endif  
-
-  myThread = 0;
-  myThreadId = 0;
+  Detach();
 }
 
 //=============================================
@@ -118,7 +98,7 @@ void OSD_Thread::SetPriority (const Standard_Integer thePriority)
 void OSD_Thread::SetFunction (const OSD_ThreadFunction &func)
 {
   // close current handle if any
-  Destroy();
+  Detach();
   myFunc = func;
 }
 
@@ -141,7 +121,7 @@ static DWORD WINAPI WNTthread_func (LPVOID data)
 }
 #endif
 
-Standard_Boolean OSD_Thread::Run (const Standard_Address data, 
+Standard_Boolean OSD_Thread::Run (const Standard_Address data,
 #ifdef _WIN32
                                   const Standard_Integer WNTStackSize
 #else
@@ -151,15 +131,11 @@ Standard_Boolean OSD_Thread::Run (const Standard_Address data,
 {
   if ( ! myFunc ) return Standard_False;
 
-  myThreadId = 0;
+  // detach current thread, if open
+  Detach();
 
 #ifdef _WIN32
 
-  // On Windows, close current handle if open
-  if ( myThread ) 
-    CloseHandle ( myThread );
-  myThread = 0;
-
   // allocate intermediate data structure to pass both data parameter and address
   // of the real thread function to Windows thread wrapper function
   WNTthread_data *adata = (WNTthread_data*)malloc ( sizeof(WNTthread_data) );
@@ -167,8 +143,8 @@ Standard_Boolean OSD_Thread::Run (const Standard_Address data,
   adata->data = data;
   adata->func = myFunc;
 
-  // then try to create a new thread 
-  
+  // then try to create a new thread
+
   myThread = CreateThread ( NULL, WNTStackSize, WNTthread_func,
                             adata, 0, &myThreadId );
   if ( myThread )
@@ -180,12 +156,15 @@ Standard_Boolean OSD_Thread::Run (const Standard_Address data,
 
 #else
 
-  // On Unix/Linux, create a new thread
-  if ( pthread_create ( &myThread, 0, myFunc, data ) )
+  if (pthread_create (&myThread, 0, myFunc, data) != 0)
+  {
     myThread = 0;
-  else myThreadId = myThread;
-
-#endif  
+  }
+  else
+  {
+    myThreadId = myThread;
+  }
+#endif
   return myThread != 0;
 }
 
@@ -197,17 +176,17 @@ void OSD_Thread::Detach ()
 {
 #ifdef _WIN32
 
-  // On Windows, close current handle 
-  if ( myThread ) 
+  // On Windows, close current handle
+  if ( myThread )
     CloseHandle ( myThread );
 
 #else
 
   // On Unix/Linux, detach a thread
-  if ( myThread ) 
+  if ( myThread )
     pthread_detach ( myThread );
 
-#endif  
+#endif
 
   myThread = 0;
   myThreadId = 0;
@@ -217,63 +196,74 @@ void OSD_Thread::Detach ()
 // OSD_Thread::Wait
 //=============================================
 
-Standard_Boolean OSD_Thread::Wait () const
-{
-  Standard_Address aRes = 0;
-  return Wait ( aRes );
-}
-
-//=============================================
-// OSD_Thread::Wait
-//=============================================
-
-Standard_Boolean OSD_Thread::Wait (Standard_Address &result) const
+Standard_Boolean OSD_Thread::Wait (Standard_Address& theResult)
 {
   // check that thread handle is not null
-  result = 0;
-  if ( ! myThread ) 
+  theResult = 0;
+  if (!myThread)
+  {
     return Standard_False;
+  }
 
 #ifdef _WIN32
-
   // On Windows, wait for the thread handle to be signaled
-  if ( WaitForSingleObject ( myThread, INFINITE ) != WAIT_OBJECT_0 ) 
+  if (WaitForSingleObject (myThread, INFINITE) != WAIT_OBJECT_0)
+  {
     return Standard_False;
+  }
 
   // and convert result of the thread execution to Standard_Address
   DWORD anExitCode;
-  if ( GetExitCodeThread ( myThread, &anExitCode ) )
-    result = ULongToPtr (anExitCode);
-  return Standard_True;
+  if (GetExitCodeThread (myThread, &anExitCode))
+  {
+    theResult = ULongToPtr (anExitCode);
+  }
 
+  CloseHandle (myThread);
+  myThread   = 0;
+  myThreadId = 0;
+  return Standard_True;
 #else
-
   // On Unix/Linux, join the thread
-  return ! pthread_join ( myThread, &result );
+  if (pthread_join (myThread, &theResult) != 0)
+  {
+    return Standard_False;
+  }
 
-#endif  
+  myThread   = 0;
+  myThreadId = 0;
+  return Standard_True;
+#endif
 }
 
 //=============================================
 // OSD_Thread::Wait
 //=============================================
 
-Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs, Standard_Address &result) const
+Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs,
+                                   Standard_Address& theResult)
 {
   // check that thread handle is not null
-  result = 0;
-  if ( ! myThread ) 
+  theResult = 0;
+  if (!myThread)
+  {
     return Standard_False;
+  }
 
 #ifdef _WIN32
-
   // On Windows, wait for the thread handle to be signaled
   DWORD ret = WaitForSingleObject (myThread, theTimeMs);
   if (ret == WAIT_OBJECT_0)
   {
     DWORD anExitCode;
-    if ( GetExitCodeThread ( myThread, &anExitCode ) )
-      result = ULongToPtr (anExitCode);
+    if (GetExitCodeThread (myThread, &anExitCode))
+    {
+      theResult = ULongToPtr (anExitCode);
+    }
+
+    CloseHandle (myThread);
+    myThread   = 0;
+    myThreadId = 0;
     return Standard_True;
   }
   else if (ret == WAIT_TIMEOUT)
@@ -282,7 +272,6 @@ Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs, Standard_Ad
   }
 
   return Standard_False;
-
 #else
   #if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
     #if __GLIBC_PREREQ(2,4)
@@ -302,13 +291,22 @@ Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs, Standard_Ad
     aTimeout.tv_sec  += aSeconds;
     aTimeout.tv_nsec += aMicroseconds * 1000;
 
-    return pthread_timedjoin_np (myThread, &result, &aTimeout) == 0;
+    if (pthread_timedjoin_np (myThread, &theResult, &aTimeout) != 0)
+    {
+      return Standard_False;
+    }
+
   #else
     // join the thread without timeout
     (void )theTimeMs;
-    return pthread_join (myThread, &result) == 0;
+    if (pthread_join (myThread, &theResult) != 0)
+    {
+      return Standard_False;
+    }
   #endif
-
+    myThread   = 0;
+    myThreadId = 0;
+    return Standard_True;
 #endif
 }
 
@@ -325,12 +323,11 @@ Standard_ThreadId OSD_Thread::GetId () const
 // OSD_Thread::Current
 //=============================================
 
-Standard_ThreadId OSD_Thread::Current () 
+Standard_ThreadId OSD_Thread::Current ()
 {
 #ifdef _WIN32
   return GetCurrentThreadId();
 #else
   return pthread_self();
-#endif  
+#endif
 }
-
index f74cbe6..527f440 100644 (file)
 
 //! A simple platform-intependent interface to execute
 //! and control threads.
-class OSD_Thread 
+class OSD_Thread
 {
 public:
 
   DEFINE_STANDARD_ALLOC
 
-  
   //! Empty constructor
   Standard_EXPORT OSD_Thread();
-  
+
   //! Initialize the tool by the thread function
   //!
   //! Note: On Windows, you might have to take an address of the thread
   //! function explicitly to pass it to this constructor without compiler error
   Standard_EXPORT OSD_Thread(const OSD_ThreadFunction& func);
-  
+
   //! Copy constructor
   Standard_EXPORT OSD_Thread(const OSD_Thread& other);
-  
+
   //! Copy thread handle from other OSD_Thread object.
   Standard_EXPORT void Assign (const OSD_Thread& other);
 void operator = (const OSD_Thread& other)
 {
   Assign(other);
 }
-  
-  //! Destructor. On Windows, closes handle to the thread.
-  //! On UNIX/Linux, does nothing.
-  Standard_EXPORT void Destroy();
-~OSD_Thread()
-{
-  Destroy();
-}
-  
+
+  //! Destructor. Detaches the thread if it wasn't done already.
+  Standard_EXPORT ~OSD_Thread();
+
   Standard_EXPORT void SetPriority (const Standard_Integer thePriority);
-  
+
   //! Initialize the tool by the thread function.
   //! If the current thread handle is not null, nullifies it.
   //!
   //! Note: On Windows, you might have to take an address of the thread
   //! function explicitly to pass it to this method without compiler error
   Standard_EXPORT void SetFunction (const OSD_ThreadFunction& func);
-  
+
   //! Starts a thread with thread function given in constructor,
   //! passing the specified input data (as void *) to it.
   //! The parameter \a WNTStackSize (on Windows only)
@@ -80,7 +74,7 @@ void operator = (const OSD_Thread& other)
   //! (by default - the same as for the current executable).
   //! Returns True if thread started successfully
   Standard_EXPORT Standard_Boolean Run (const Standard_Address data = 0, const Standard_Integer WNTStackSize = 0);
-  
+
   //! Detaches the execution thread from this Thread object,
   //! so that it cannot be waited.
   //! Note that mechanics of this operation is different on
@@ -89,9 +83,14 @@ void operator = (const OSD_Thread& other)
   //! However, the purpose is the same: to instruct the system to
   //! release all thread data upon its completion.
   Standard_EXPORT void Detach();
-  
-  Standard_EXPORT Standard_Boolean Wait() const;
-  
+
+  //! Waits till the thread finishes execution.
+  Standard_Boolean Wait()
+  {
+    Standard_Address aRes = 0;
+    return Wait (aRes);
+  }
+
   //! Wait till the thread finishes execution.
   //! Returns True if wait was successful, False in case of error.
   //!
@@ -101,45 +100,27 @@ void operator = (const OSD_Thread& other)
   //! Note however that it is advisable not to rely upon returned result
   //! value, as it is not always the value actually returned by the thread
   //! function. In addition, on Windows it is converted via DWORD.
-  Standard_EXPORT Standard_Boolean Wait (Standard_Address& result) const;
-  
+  Standard_EXPORT Standard_Boolean Wait (Standard_Address& theResult);
+
   //! Waits for some time and if the thread is finished,
   //! it returns the result.
   //! The function returns false if the thread is not finished yet.
-  Standard_EXPORT Standard_Boolean Wait (const Standard_Integer time, Standard_Address& result) const;
-  
+  Standard_EXPORT Standard_Boolean Wait (const Standard_Integer time, Standard_Address& theResult);
+
   //! Returns ID of the currently controlled thread ID,
   //! or 0 if no thread is run
   Standard_EXPORT Standard_ThreadId GetId() const;
-  
+
   //! Auxiliary: returns ID of the current thread
   Standard_EXPORT static Standard_ThreadId Current();
 
-
-
-
-protected:
-
-
-
-
-
 private:
 
-
-
   OSD_ThreadFunction myFunc;
   OSD_PThread myThread;
   Standard_ThreadId myThreadId;
   Standard_Integer myPriority;
 
-
 };
 
-
-
-
-
-
-
 #endif // _OSD_Thread_HeaderFile