0028657: Foundation Classes - OSD_Thread does not release thread resources on non...
[occt.git] / src / OSD / OSD_Thread.cxx
CommitLineData
b311480e 1// Created on: 2006-04-12
2// Created by: Andrey BETENEV
973c2be1 3// Copyright (c) 2006-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
7fd59977 15
42cf5bc1 16#include <OSD_Thread.hxx>
7fd59977 17
18//=============================================
19// OSD_Thread::OSD_Thread
20//=============================================
7fd59977 21OSD_Thread::OSD_Thread ()
22 : myFunc(0), myThread(0), myThreadId(0), myPriority(0)
23{}
24
25//=============================================
26// OSD_Thread::OSD_Thread
27//=============================================
28
29OSD_Thread::OSD_Thread (const OSD_ThreadFunction &func)
30 : myFunc(func), myThread(0), myThreadId(0), myPriority(0)
31{}
32
33//=============================================
34// OSD_Thread::OSD_Thread
35//=============================================
36
37OSD_Thread::OSD_Thread (const OSD_Thread &other)
38 : myFunc(other.myFunc), myThread(0), myThreadId(0)
39{
40 Assign ( other );
41}
42
43//=============================================
44// OSD_Thread::Assign
45//=============================================
46
47void OSD_Thread::Assign (const OSD_Thread &other)
48{
b2ec0b4d 49 // copy function pointer
7fd59977 50 myFunc = other.myFunc;
51 myPriority = other.myPriority;
52
b2ec0b4d 53 // detach current thread
54 Detach();
7fd59977 55
b2ec0b4d 56#ifdef _WIN32
57 // duplicate the source handle
7fd59977 58 if ( other.myThread ) {
59 HANDLE hProc = GetCurrentProcess(); // we are always within the same process
60 DuplicateHandle ( hProc, other.myThread, hProc, &myThread,
61 0, TRUE, DUPLICATE_SAME_ACCESS );
62 }
7fd59977 63#else
7fd59977 64 // On Unix/Linux, just copy the thread id
65 myThread = other.myThread;
b2ec0b4d 66#endif
7fd59977 67
68 myThreadId = other.myThreadId;
69}
70
71//=============================================
b2ec0b4d 72// OSD_Thread::~OSD_Thread
7fd59977 73//=============================================
74
b2ec0b4d 75OSD_Thread::~OSD_Thread()
7fd59977 76{
b2ec0b4d 77 Detach();
7fd59977 78}
79
80//=============================================
81//function : SetPriority
82//purpose : Set the thread priority relative to the caller's priority
83//=============================================
84
85void OSD_Thread::SetPriority (const Standard_Integer thePriority)
86{
87 myPriority = thePriority;
57c28b61 88#ifdef _WIN32
7fd59977 89 if (myThread)
90 SetThreadPriority (myThread, thePriority);
91#endif
92}
93
94//=============================================
95// OSD_Thread::SetFunction
96//=============================================
97
98void OSD_Thread::SetFunction (const OSD_ThreadFunction &func)
99{
100 // close current handle if any
b2ec0b4d 101 Detach();
7fd59977 102 myFunc = func;
103}
104
105//=============================================
106// OSD_Thread::Run
107//=============================================
108
57c28b61 109#ifdef _WIN32
7fd59977 110#include <malloc.h>
111// On Windows the signature of the thread function differs from that on UNIX/Linux.
112// As we use the same definition of the thread function on all platforms (POSIX-like),
113// we need to introduce appropriate wrapper function on Windows.
114struct WNTthread_data { void *data; OSD_ThreadFunction func; };
115static DWORD WINAPI WNTthread_func (LPVOID data)
116{
117 WNTthread_data *adata = (WNTthread_data*)data;
118 void* ret = adata->func ( adata->data );
119 free ( adata );
68299304 120 return PtrToLong (ret);
7fd59977 121}
122#endif
123
b2ec0b4d 124Standard_Boolean OSD_Thread::Run (const Standard_Address data,
57c28b61 125#ifdef _WIN32
7fd59977 126 const Standard_Integer WNTStackSize
127#else
128 const Standard_Integer
129#endif
130 )
131{
132 if ( ! myFunc ) return Standard_False;
133
b2ec0b4d 134 // detach current thread, if open
135 Detach();
7fd59977 136
57c28b61 137#ifdef _WIN32
7fd59977 138
7fd59977 139 // allocate intermediate data structure to pass both data parameter and address
140 // of the real thread function to Windows thread wrapper function
141 WNTthread_data *adata = (WNTthread_data*)malloc ( sizeof(WNTthread_data) );
142 if ( ! adata ) return Standard_False;
143 adata->data = data;
144 adata->func = myFunc;
145
b2ec0b4d 146 // then try to create a new thread
147
7fd59977 148 myThread = CreateThread ( NULL, WNTStackSize, WNTthread_func,
149 adata, 0, &myThreadId );
150 if ( myThread )
151 SetThreadPriority (myThread, myPriority);
152 else {
153 memset ( adata, 0, sizeof(WNTthread_data) );
154 free ( adata );
155 }
156
157#else
158
b2ec0b4d 159 if (pthread_create (&myThread, 0, myFunc, data) != 0)
160 {
7fd59977 161 myThread = 0;
b2ec0b4d 162 }
163 else
164 {
165 myThreadId = myThread;
166 }
167#endif
7fd59977 168 return myThread != 0;
169}
170
171//=============================================
172// OSD_Thread::Detach
173//=============================================
174
175void OSD_Thread::Detach ()
176{
57c28b61 177#ifdef _WIN32
7fd59977 178
b2ec0b4d 179 // On Windows, close current handle
180 if ( myThread )
7fd59977 181 CloseHandle ( myThread );
182
183#else
184
185 // On Unix/Linux, detach a thread
b2ec0b4d 186 if ( myThread )
7fd59977 187 pthread_detach ( myThread );
188
b2ec0b4d 189#endif
7fd59977 190
191 myThread = 0;
192 myThreadId = 0;
193}
194
195//=============================================
196// OSD_Thread::Wait
197//=============================================
198
b2ec0b4d 199Standard_Boolean OSD_Thread::Wait (Standard_Address& theResult)
7fd59977 200{
201 // check that thread handle is not null
b2ec0b4d 202 theResult = 0;
203 if (!myThread)
204 {
7fd59977 205 return Standard_False;
b2ec0b4d 206 }
7fd59977 207
57c28b61 208#ifdef _WIN32
7fd59977 209 // On Windows, wait for the thread handle to be signaled
b2ec0b4d 210 if (WaitForSingleObject (myThread, INFINITE) != WAIT_OBJECT_0)
211 {
7fd59977 212 return Standard_False;
b2ec0b4d 213 }
7fd59977 214
215 // and convert result of the thread execution to Standard_Address
216 DWORD anExitCode;
b2ec0b4d 217 if (GetExitCodeThread (myThread, &anExitCode))
218 {
219 theResult = ULongToPtr (anExitCode);
220 }
7fd59977 221
b2ec0b4d 222 CloseHandle (myThread);
223 myThread = 0;
224 myThreadId = 0;
225 return Standard_True;
7fd59977 226#else
7fd59977 227 // On Unix/Linux, join the thread
b2ec0b4d 228 if (pthread_join (myThread, &theResult) != 0)
229 {
230 return Standard_False;
231 }
7fd59977 232
b2ec0b4d 233 myThread = 0;
234 myThreadId = 0;
235 return Standard_True;
236#endif
7fd59977 237}
238
239//=============================================
240// OSD_Thread::Wait
241//=============================================
242
b2ec0b4d 243Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs,
244 Standard_Address& theResult)
7fd59977 245{
246 // check that thread handle is not null
b2ec0b4d 247 theResult = 0;
248 if (!myThread)
249 {
7fd59977 250 return Standard_False;
b2ec0b4d 251 }
7fd59977 252
57c28b61 253#ifdef _WIN32
7fd59977 254 // On Windows, wait for the thread handle to be signaled
c85385c0 255 DWORD ret = WaitForSingleObject (myThread, theTimeMs);
7fd59977 256 if (ret == WAIT_OBJECT_0)
257 {
258 DWORD anExitCode;
b2ec0b4d 259 if (GetExitCodeThread (myThread, &anExitCode))
260 {
261 theResult = ULongToPtr (anExitCode);
262 }
263
264 CloseHandle (myThread);
265 myThread = 0;
266 myThreadId = 0;
7fd59977 267 return Standard_True;
268 }
269 else if (ret == WAIT_TIMEOUT)
270 {
271 return Standard_False;
272 }
273
274 return Standard_False;
7fd59977 275#else
c85385c0 276 #if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
277 #if __GLIBC_PREREQ(2,4)
278 #define HAS_TIMED_NP
279 #endif
280 #endif
281
282 #ifdef HAS_TIMED_NP
283 struct timespec aTimeout;
284 if (clock_gettime (CLOCK_REALTIME, &aTimeout) == -1)
285 {
286 return Standard_False;
287 }
288
289 time_t aSeconds = (theTimeMs / 1000);
290 long aMicroseconds = (theTimeMs - aSeconds * 1000) * 1000;
291 aTimeout.tv_sec += aSeconds;
292 aTimeout.tv_nsec += aMicroseconds * 1000;
293
b2ec0b4d 294 if (pthread_timedjoin_np (myThread, &theResult, &aTimeout) != 0)
295 {
296 return Standard_False;
297 }
298
c85385c0 299 #else
300 // join the thread without timeout
301 (void )theTimeMs;
b2ec0b4d 302 if (pthread_join (myThread, &theResult) != 0)
303 {
304 return Standard_False;
305 }
c85385c0 306 #endif
b2ec0b4d 307 myThread = 0;
308 myThreadId = 0;
309 return Standard_True;
c85385c0 310#endif
7fd59977 311}
312
313//=============================================
314// OSD_Thread::GetId
315//=============================================
316
317Standard_ThreadId OSD_Thread::GetId () const
318{
319 return myThreadId;
320}
321
322//=============================================
323// OSD_Thread::Current
324//=============================================
325
b2ec0b4d 326Standard_ThreadId OSD_Thread::Current ()
7fd59977 327{
57c28b61 328#ifdef _WIN32
7fd59977 329 return GetCurrentThreadId();
330#else
331 return pthread_self();
b2ec0b4d 332#endif
7fd59977 333}