0031687: Draw Harness, ViewerTest - extend command vrenderparams with option updating...
[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
2b2be3fb 147 DWORD aThreadId = DWORD();
7fd59977 148 myThread = CreateThread ( NULL, WNTStackSize, WNTthread_func,
2b2be3fb 149 adata, 0, &aThreadId );
150 myThreadId = aThreadId;
7fd59977 151 if ( myThread )
152 SetThreadPriority (myThread, myPriority);
153 else {
154 memset ( adata, 0, sizeof(WNTthread_data) );
155 free ( adata );
156 }
157
158#else
159
b2ec0b4d 160 if (pthread_create (&myThread, 0, myFunc, data) != 0)
161 {
7fd59977 162 myThread = 0;
b2ec0b4d 163 }
164 else
165 {
2b2be3fb 166 myThreadId = (Standard_ThreadId)myThread;
b2ec0b4d 167 }
168#endif
7fd59977 169 return myThread != 0;
170}
171
172//=============================================
173// OSD_Thread::Detach
174//=============================================
175
176void OSD_Thread::Detach ()
177{
57c28b61 178#ifdef _WIN32
7fd59977 179
b2ec0b4d 180 // On Windows, close current handle
181 if ( myThread )
7fd59977 182 CloseHandle ( myThread );
183
184#else
185
186 // On Unix/Linux, detach a thread
b2ec0b4d 187 if ( myThread )
7fd59977 188 pthread_detach ( myThread );
189
b2ec0b4d 190#endif
7fd59977 191
192 myThread = 0;
193 myThreadId = 0;
194}
195
196//=============================================
197// OSD_Thread::Wait
198//=============================================
199
b2ec0b4d 200Standard_Boolean OSD_Thread::Wait (Standard_Address& theResult)
7fd59977 201{
202 // check that thread handle is not null
b2ec0b4d 203 theResult = 0;
204 if (!myThread)
205 {
7fd59977 206 return Standard_False;
b2ec0b4d 207 }
7fd59977 208
57c28b61 209#ifdef _WIN32
7fd59977 210 // On Windows, wait for the thread handle to be signaled
b2ec0b4d 211 if (WaitForSingleObject (myThread, INFINITE) != WAIT_OBJECT_0)
212 {
7fd59977 213 return Standard_False;
b2ec0b4d 214 }
7fd59977 215
216 // and convert result of the thread execution to Standard_Address
217 DWORD anExitCode;
b2ec0b4d 218 if (GetExitCodeThread (myThread, &anExitCode))
219 {
220 theResult = ULongToPtr (anExitCode);
221 }
7fd59977 222
b2ec0b4d 223 CloseHandle (myThread);
224 myThread = 0;
225 myThreadId = 0;
226 return Standard_True;
7fd59977 227#else
7fd59977 228 // On Unix/Linux, join the thread
b2ec0b4d 229 if (pthread_join (myThread, &theResult) != 0)
230 {
231 return Standard_False;
232 }
7fd59977 233
b2ec0b4d 234 myThread = 0;
235 myThreadId = 0;
236 return Standard_True;
237#endif
7fd59977 238}
239
240//=============================================
241// OSD_Thread::Wait
242//=============================================
243
b2ec0b4d 244Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs,
245 Standard_Address& theResult)
7fd59977 246{
247 // check that thread handle is not null
b2ec0b4d 248 theResult = 0;
249 if (!myThread)
250 {
7fd59977 251 return Standard_False;
b2ec0b4d 252 }
7fd59977 253
57c28b61 254#ifdef _WIN32
7fd59977 255 // On Windows, wait for the thread handle to be signaled
c85385c0 256 DWORD ret = WaitForSingleObject (myThread, theTimeMs);
7fd59977 257 if (ret == WAIT_OBJECT_0)
258 {
259 DWORD anExitCode;
b2ec0b4d 260 if (GetExitCodeThread (myThread, &anExitCode))
261 {
262 theResult = ULongToPtr (anExitCode);
263 }
264
265 CloseHandle (myThread);
266 myThread = 0;
267 myThreadId = 0;
7fd59977 268 return Standard_True;
269 }
270 else if (ret == WAIT_TIMEOUT)
271 {
272 return Standard_False;
273 }
274
275 return Standard_False;
7fd59977 276#else
c85385c0 277 #if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
278 #if __GLIBC_PREREQ(2,4)
279 #define HAS_TIMED_NP
280 #endif
281 #endif
282
283 #ifdef HAS_TIMED_NP
284 struct timespec aTimeout;
285 if (clock_gettime (CLOCK_REALTIME, &aTimeout) == -1)
286 {
287 return Standard_False;
288 }
289
290 time_t aSeconds = (theTimeMs / 1000);
291 long aMicroseconds = (theTimeMs - aSeconds * 1000) * 1000;
292 aTimeout.tv_sec += aSeconds;
293 aTimeout.tv_nsec += aMicroseconds * 1000;
294
b2ec0b4d 295 if (pthread_timedjoin_np (myThread, &theResult, &aTimeout) != 0)
296 {
297 return Standard_False;
298 }
299
c85385c0 300 #else
301 // join the thread without timeout
302 (void )theTimeMs;
b2ec0b4d 303 if (pthread_join (myThread, &theResult) != 0)
304 {
305 return Standard_False;
306 }
c85385c0 307 #endif
b2ec0b4d 308 myThread = 0;
309 myThreadId = 0;
310 return Standard_True;
c85385c0 311#endif
7fd59977 312}
313
314//=============================================
315// OSD_Thread::GetId
316//=============================================
317
318Standard_ThreadId OSD_Thread::GetId () const
319{
320 return myThreadId;
321}
322
323//=============================================
324// OSD_Thread::Current
325//=============================================
326
b2ec0b4d 327Standard_ThreadId OSD_Thread::Current ()
7fd59977 328{
57c28b61 329#ifdef _WIN32
7fd59977 330 return GetCurrentThreadId();
331#else
2b2be3fb 332 return (Standard_ThreadId)pthread_self();
b2ec0b4d 333#endif
7fd59977 334}