0030550: Coding - Integer overflow in Standard_CString HashCodes
[occt.git] / src / OSD / OSD_Thread.cxx
1 // Created on: 2006-04-12
2 // Created by: Andrey BETENEV
3 // Copyright (c) 2006-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OSD_Thread.hxx>
17
18 //=============================================
19 // OSD_Thread::OSD_Thread
20 //=============================================
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 {
49   // copy function pointer
50   myFunc = other.myFunc;
51   myPriority = other.myPriority;
52
53   // detach current thread
54   Detach();
55
56 #ifdef _WIN32
57   // duplicate the source handle
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   }
63 #else
64   // On Unix/Linux, just copy the thread id
65   myThread = other.myThread;
66 #endif
67
68   myThreadId = other.myThreadId;
69 }
70
71 //=============================================
72 // OSD_Thread::~OSD_Thread
73 //=============================================
74
75 OSD_Thread::~OSD_Thread()
76 {
77   Detach();
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;
88 #ifdef _WIN32
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
101   Detach();
102   myFunc = func;
103 }
104
105 //=============================================
106 // OSD_Thread::Run
107 //=============================================
108
109 #ifdef _WIN32
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 );
120   return PtrToLong (ret);
121 }
122 #endif
123
124 Standard_Boolean OSD_Thread::Run (const Standard_Address data,
125 #ifdef _WIN32
126                                   const Standard_Integer WNTStackSize
127 #else
128                                   const Standard_Integer
129 #endif
130                                   )
131 {
132   if ( ! myFunc ) return Standard_False;
133
134   // detach current thread, if open
135   Detach();
136
137 #ifdef _WIN32
138
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
146   // then try to create a new thread
147   DWORD aThreadId = DWORD();
148   myThread = CreateThread ( NULL, WNTStackSize, WNTthread_func,
149                             adata, 0, &aThreadId );
150   myThreadId = aThreadId;
151   if ( myThread )
152     SetThreadPriority (myThread, myPriority);
153   else {
154     memset ( adata, 0, sizeof(WNTthread_data) );
155     free ( adata );
156   }
157
158 #else
159
160   if (pthread_create (&myThread, 0, myFunc, data) != 0)
161   {
162     myThread = 0;
163   }
164   else
165   {
166     myThreadId = (Standard_ThreadId)myThread;
167   }
168 #endif
169   return myThread != 0;
170 }
171
172 //=============================================
173 // OSD_Thread::Detach
174 //=============================================
175
176 void OSD_Thread::Detach ()
177 {
178 #ifdef _WIN32
179
180   // On Windows, close current handle
181   if ( myThread )
182     CloseHandle ( myThread );
183
184 #else
185
186   // On Unix/Linux, detach a thread
187   if ( myThread )
188     pthread_detach ( myThread );
189
190 #endif
191
192   myThread = 0;
193   myThreadId = 0;
194 }
195
196 //=============================================
197 // OSD_Thread::Wait
198 //=============================================
199
200 Standard_Boolean OSD_Thread::Wait (Standard_Address& theResult)
201 {
202   // check that thread handle is not null
203   theResult = 0;
204   if (!myThread)
205   {
206     return Standard_False;
207   }
208
209 #ifdef _WIN32
210   // On Windows, wait for the thread handle to be signaled
211   if (WaitForSingleObject (myThread, INFINITE) != WAIT_OBJECT_0)
212   {
213     return Standard_False;
214   }
215
216   // and convert result of the thread execution to Standard_Address
217   DWORD anExitCode;
218   if (GetExitCodeThread (myThread, &anExitCode))
219   {
220     theResult = ULongToPtr (anExitCode);
221   }
222
223   CloseHandle (myThread);
224   myThread   = 0;
225   myThreadId = 0;
226   return Standard_True;
227 #else
228   // On Unix/Linux, join the thread
229   if (pthread_join (myThread, &theResult) != 0)
230   {
231     return Standard_False;
232   }
233
234   myThread   = 0;
235   myThreadId = 0;
236   return Standard_True;
237 #endif
238 }
239
240 //=============================================
241 // OSD_Thread::Wait
242 //=============================================
243
244 Standard_Boolean OSD_Thread::Wait (const Standard_Integer theTimeMs,
245                                    Standard_Address& theResult)
246 {
247   // check that thread handle is not null
248   theResult = 0;
249   if (!myThread)
250   {
251     return Standard_False;
252   }
253
254 #ifdef _WIN32
255   // On Windows, wait for the thread handle to be signaled
256   DWORD ret = WaitForSingleObject (myThread, theTimeMs);
257   if (ret == WAIT_OBJECT_0)
258   {
259     DWORD anExitCode;
260     if (GetExitCodeThread (myThread, &anExitCode))
261     {
262       theResult = ULongToPtr (anExitCode);
263     }
264
265     CloseHandle (myThread);
266     myThread   = 0;
267     myThreadId = 0;
268     return Standard_True;
269   }
270   else if (ret == WAIT_TIMEOUT)
271   {
272     return Standard_False;
273   }
274
275   return Standard_False;
276 #else
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
295     if (pthread_timedjoin_np (myThread, &theResult, &aTimeout) != 0)
296     {
297       return Standard_False;
298     }
299
300   #else
301     // join the thread without timeout
302     (void )theTimeMs;
303     if (pthread_join (myThread, &theResult) != 0)
304     {
305       return Standard_False;
306     }
307   #endif
308     myThread   = 0;
309     myThreadId = 0;
310     return Standard_True;
311 #endif
312 }
313
314 //=============================================
315 // OSD_Thread::GetId
316 //=============================================
317
318 Standard_ThreadId OSD_Thread::GetId () const
319 {
320   return myThreadId;
321 }
322
323 //=============================================
324 // OSD_Thread::Current
325 //=============================================
326
327 Standard_ThreadId OSD_Thread::Current ()
328 {
329 #ifdef _WIN32
330   return GetCurrentThreadId();
331 #else
332   return (Standard_ThreadId)pthread_self();
333 #endif
334 }