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 |
21 | OSD_Thread::OSD_Thread () |
22 | : myFunc(0), myThread(0), myThreadId(0), myPriority(0) |
23 | {} |
24 | |
25 | //============================================= |
26 | // OSD_Thread::OSD_Thread |
27 | //============================================= |
28 | |
29 | OSD_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 | |
37 | OSD_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 | |
47 | void 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 |
75 | OSD_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 | |
85 | void 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 | |
98 | void 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. |
114 | struct WNTthread_data { void *data; OSD_ThreadFunction func; }; |
115 | static 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 |
124 | Standard_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 | |
175 | void 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 |
199 | Standard_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 |
243 | Standard_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 | |
317 | Standard_ThreadId OSD_Thread::GetId () const |
318 | { |
319 | return myThreadId; |
320 | } |
321 | |
322 | //============================================= |
323 | // OSD_Thread::Current |
324 | //============================================= |
325 | |
b2ec0b4d |
326 | Standard_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 | } |