1 karl 1.89 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.71 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.56 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.71 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.75 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.89 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 chip 1.11 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
18 mike 1.2 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.89 //
|
21 chip 1.11 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
24 chip 1.11 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
27 mike 1.2 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include "Thread.h"
|
35 mike 1.96 #include <errno.h>
|
36 kumpf 1.68 #include <exception>
|
37 kumpf 1.14 #include <Pegasus/Common/Tracer.h>
|
38 kumpf 1.103 #include <Pegasus/Common/AutoPtr.h>
|
39 mike 1.91 #include "Time.h"
|
40 mike 1.2
|
41 mike 1.91 PEGASUS_USING_STD;
|
42 mike 1.2
43 PEGASUS_NAMESPACE_BEGIN
44
|
45 mike 1.91 //==============================================================================
46 //
47 // POSIX Threads Implementation:
48 //
49 //==============================================================================
|
50 mday 1.42
|
51 mike 1.91 #if defined(PEGASUS_HAVE_PTHREADS)
52
53 struct StartWrapperArg
|
54 chip 1.11 {
|
55 mike 1.91 void *(PEGASUS_THREAD_CDECL * start) (void *);
56 void *arg;
57 };
|
58 mike 1.2
|
59 mike 1.91 extern "C" void *_start_wrapper(void *arg_)
|
60 chuck 1.43 {
|
61 kumpf 1.104 // Clean up dynamic memory now to prevent a leak if the thread is canceled.
62 StartWrapperArg arg;
63 arg.start = ((StartWrapperArg *) arg_)->start;
64 arg.arg = ((StartWrapperArg *) arg_)->arg;
65 delete (StartWrapperArg *) arg_;
|
66 chuck 1.43
|
67 marek 1.105 // establish cancelability of the thread
68 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
69 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
70
|
71 kumpf 1.104 void *return_value = (*arg.start) (arg.arg);
|
72 chuck 1.37
|
73 mike 1.91 return return_value;
74 }
|
75 mike 1.2
|
76 mike 1.91 void Thread::cancel()
|
77 mike 1.2 {
|
78 mike 1.94 pthread_cancel(_handle.thid.thread);
|
79 mike 1.2 }
|
80 kumpf 1.81
|
81 mike 1.91 void Thread::thread_switch()
82 {
83 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
84 pthread_yield(NULL);
85 #else
86 sched_yield();
|
87 mike 1.2 #endif
|
88 mike 1.91 }
|
89 mike 1.2
|
90 mike 1.91 void Thread::sleep(Uint32 msec)
|
91 chuck 1.39 {
|
92 mike 1.91 Threads::sleep(msec);
|
93 chuck 1.37 }
94
|
95 kumpf 1.98 void Thread::join()
|
96 chuck 1.37 {
|
97 mike 1.94 if (!_is_detached && !Threads::null(_handle.thid))
98 pthread_join(_handle.thid.thread, &_exit_code);
|
99 kumpf 1.81
|
100 mike 1.91 Threads::clear(_handle.thid);
|
101 chuck 1.37 }
102
|
103 kumpf 1.98 void Thread::detach()
|
104 chuck 1.37 {
|
105 mike 1.91 _is_detached = true;
106 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
|
107 mike 1.94 pthread_t thread_id=_handle.thid.thread;
|
108 mike 1.91 pthread_detach(&thread_id);
109 #else
|
110 mike 1.94 pthread_detach(_handle.thid.thread);
|
111 mike 1.91 #endif
|
112 chuck 1.37 }
113
|
114 mike 1.91 ThreadStatus Thread::run()
115 {
116 StartWrapperArg *arg = new StartWrapperArg;
117 arg->start = _start;
118 arg->arg = this;
|
119 mday 1.52
|
120 mike 1.91 Threads::Type type = _is_detached ? Threads::DETACHED : Threads::JOINABLE;
121 int rc = Threads::create(_handle.thid, type, _start_wrapper, arg);
|
122 kumpf 1.81
|
123 kumpf 1.98 // On Linux distributions released prior 2005, the implementation of
|
124 mike 1.91 // Native POSIX Thread Library returns ENOMEM instead of EAGAIN when
|
125 kumpf 1.98 // there
|
126 mike 1.91 // are no insufficient memory. Hence we are checking for both. See bug
127 // 386.
|
128 mday 1.58
|
129 marek 1.93 if (rc == -1)
130 rc = errno;
|
131 mike 1.91 if ((rc == EAGAIN) || (rc == ENOMEM))
|
132 kumpf 1.81 {
|
133 mike 1.91 Threads::clear(_handle.thid);
134 delete arg;
135 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
136 kumpf 1.81 }
|
137 mike 1.91 else if (rc != 0)
|
138 kumpf 1.81 {
|
139 mike 1.91 Threads::clear(_handle.thid);
140 delete arg;
141 return PEGASUS_THREAD_SETUP_FAILURE;
|
142 kumpf 1.81 }
|
143 mike 1.91 return PEGASUS_THREAD_OK;
144 }
|
145 mday 1.58
|
146 kumpf 1.98 Thread::Thread(
147 ThreadReturnType(PEGASUS_THREAD_CDECL* start) (void*),
148 void* parameter,
149 Boolean detached)
150 : _is_detached(detached),
151 _start(start),
152 _cleanup(),
153 _tsd(),
154 _thread_parm(parameter),
155 _exit_code(0)
|
156 mike 1.91 {
157 Threads::clear(_handle.thid);
|
158 kumpf 1.81 }
|
159 mday 1.20
|
160 mike 1.91 Thread::~Thread()
|
161 mday 1.20 {
|
162 kumpf 1.81 try
163 {
|
164 mike 1.91 join();
165 empty_tsd();
|
166 kumpf 1.81 }
|
167 kumpf 1.98 catch (...)
|
168 kumpf 1.81 {
|
169 mike 1.91 // Do not allow the destructor to throw an exception
|
170 kumpf 1.81 }
|
171 mday 1.20 }
172
|
173 mike 1.91 #endif /* PEGASUS_HAVE_PTHREADS */
174
175 //==============================================================================
176 //
177 // Windows Threads Implementation:
178 //
179 //==============================================================================
|
180 kumpf 1.81
|
181 mike 1.91 #if defined(PEGASUS_HAVE_WINDOWS_THREADS)
|
182 kumpf 1.81
|
183 kumpf 1.98 ThreadStatus Thread::run()
|
184 mike 1.91 {
185 // Note: A Win32 thread ID is not the same thing as a pthread ID.
186 // Win32 threads have both a thread ID and a handle. The handle
187 // is used in the wait functions, etc.
188 // So _handle.thid is actually the thread handle.
|
189 kumpf 1.81
|
190 mike 1.91 unsigned threadid = 0;
|
191 mike 1.2
|
192 mike 1.91 ThreadType tt;
193 tt.handle = (HANDLE) _beginthreadex(NULL, 0, _start, this, 0, &threadid);
194 _handle.thid = tt;
|
195 chuck 1.39
|
196 mike 1.95 if (Threads::null(_handle.thid))
|
197 mike 1.91 {
198 if (errno == EAGAIN)
|
199 kumpf 1.81 {
|
200 mike 1.91 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
201 kumpf 1.81 }
|
202 mike 1.91 else
|
203 kumpf 1.81 {
|
204 mike 1.91 return PEGASUS_THREAD_SETUP_FAILURE;
|
205 kumpf 1.81 }
|
206 mike 1.91 }
207 return PEGASUS_THREAD_OK;
208 }
|
209 mday 1.52
|
210 kumpf 1.98 void Thread::cancel()
|
211 mike 1.91 {
212 _cancelled = true;
213 }
|
214 kumpf 1.82
|
215 kumpf 1.98 void Thread::thread_switch()
|
216 mike 1.91 {
217 Sleep(0);
218 }
|
219 kumpf 1.82
|
220 mike 1.91 void Thread::sleep(Uint32 milliseconds)
221 {
222 Sleep(milliseconds);
223 }
|
224 mike 1.2
|
225 kumpf 1.98 void Thread::join()
|
226 mike 1.91 {
|
227 mike 1.95 if (!Threads::null(_handle.thid))
|
228 mike 1.91 {
229 if (!_is_detached)
230 {
231 if (!_cancelled)
|
232 kumpf 1.82 {
|
233 mike 1.91 // Emulate the unix join api. Caller sleeps until thread is
234 // done.
235 WaitForSingleObject(_handle.thid.handle, INFINITE);
|
236 kumpf 1.82 }
|
237 mike 1.91 else
|
238 kumpf 1.82 {
|
239 mike 1.91 // Currently this is the only way to ensure this code does
|
240 kumpf 1.98 // not
|
241 mike 1.91 // hang forever.
242 if (WaitForSingleObject(_handle.thid.handle, 10000) ==
243 WAIT_TIMEOUT)
|
244 kumpf 1.82 {
|
245 mike 1.91 TerminateThread(_handle.thid.handle, 0);
|
246 kumpf 1.82 }
|
247 mike 1.91 }
|
248 s.hills 1.49
|
249 mike 1.91 DWORD exit_code = 0;
250 GetExitCodeThread(_handle.thid.handle, &exit_code);
251 _exit_code = (ThreadReturnType) exit_code;
|
252 kumpf 1.81 }
|
253 mike 1.91
254 CloseHandle(_handle.thid.handle);
255 Threads::clear(_handle.thid);
|
256 kumpf 1.82 }
|
257 mike 1.91 }
|
258 kumpf 1.14
|
259 kumpf 1.98 void Thread::detach()
|
260 mike 1.2 {
|
261 mike 1.91 _is_detached = true;
262 }
|
263 kumpf 1.81
|
264 mike 1.91 Thread::Thread(ThreadReturnType(PEGASUS_THREAD_CDECL * start) (void *),
265 void *parameter,
266 Boolean detached):_is_detached(detached),
267 _cancelled(false),
268 _start(start), _cleanup(), _tsd(), _thread_parm(parameter), _exit_code(0)
269 {
270 Threads::clear(_handle.thid);
271 }
|
272 kumpf 1.81
|
273 mike 1.91 Thread::~Thread()
274 {
|
275 kumpf 1.81 try
276 {
|
277 mike 1.91 join();
278 empty_tsd();
279 }
|
280 kumpf 1.98 catch (...)
|
281 mike 1.91 {
282 }
283 }
|
284 kumpf 1.81
|
285 mike 1.91 #endif /* PEGASUS_HAVE_WINDOWS_THREADS */
|
286 kumpf 1.57
|
287 mike 1.91 //==============================================================================
288 //
289 // Common implementation:
290 //
291 //==============================================================================
|
292 kumpf 1.81
|
293 mike 1.91 void thread_data::default_delete(void *data)
294 {
295 if (data != NULL)
296 ::operator delete(data);
297 }
|
298 mike 1.2
|
299 mike 1.91 void language_delete(void *data)
300 {
301 if (data != NULL)
302 {
303 AutoPtr < AcceptLanguageList > al(static_cast <
304 AcceptLanguageList * >(data));
|
305 kumpf 1.57 }
|
306 mike 1.2 }
307
|
308 mike 1.91 Boolean Thread::_signals_blocked = false;
309 #ifndef PEGASUS_OS_ZOS
310 TSDKeyType Thread::_platform_thread_key = TSDKeyType(-1);
311 #else
312 TSDKeyType Thread::_platform_thread_key;
313 #endif
314 Boolean Thread::_key_initialized = false;
315 Boolean Thread::_key_error = false;
|
316 mday 1.12
|
317 mike 1.91 void Thread::cleanup_push(void (*routine) (void *), void *parm)
|
318 mike 1.2 {
|
319 mike 1.91 AutoPtr < cleanup_handler > cu(new cleanup_handler(routine, parm));
320 _cleanup.insert_front(cu.get());
321 cu.release();
322 return;
323 }
|
324 kumpf 1.81
|
325 mike 1.91 void Thread::cleanup_pop(Boolean execute)
326 {
327 AutoPtr < cleanup_handler > cu;
328 try
329 {
330 cu.reset(_cleanup.remove_front());
331 }
|
332 kumpf 1.98 catch (IPCException &)
|
333 mike 1.91 {
334 PEGASUS_ASSERT(0);
335 }
336 if (execute == true)
337 cu->execute();
338 }
|
339 kumpf 1.81
340
|
341 mike 1.91 void Thread::exit_self(ThreadReturnType exit_code)
342 {
|
343 ouyang.jian 1.100 #if !defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX) \
344 && !defined(PEGASUS_PLATFORM_PASE_ISERIES_IBMCXX)
|
345 marek 1.97 Threads::exit(exit_code);
|
346 mike 1.91 #else
347 // execute the cleanup stack and then return
348 while (_cleanup.size())
349 {
|
350 kumpf 1.81 try
351 {
|
352 mike 1.91 cleanup_pop(true);
|
353 kumpf 1.81 }
|
354 kumpf 1.98 catch (IPCException &)
|
355 kumpf 1.81 {
|
356 mike 1.91 PEGASUS_ASSERT(0);
|
357 kumpf 1.81 break;
358 }
|
359 mike 1.91 }
360 _exit_code = exit_code;
361 Threads::exit(exit_code);
362 Threads::clear(_handle.thid);
363 #endif
364 }
|
365 kumpf 1.81
|
366 mike 1.91 Sint8 Thread::initializeKey()
367 {
368 PEG_METHOD_ENTER(TRC_THREAD, "Thread::initializeKey");
369 if (!Thread::_key_initialized)
370 {
371 if (Thread::_key_error)
372 {
|
373 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
374 mike 1.91 "Thread: ERROR - thread key error");
375 return -1;
376 }
|
377 kumpf 1.81
|
378 mike 1.91 if (TSDKey::create(&Thread::_platform_thread_key) == 0)
|
379 kumpf 1.81 {
|
380 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
381 mike 1.91 "Thread: able to create a thread key");
382 Thread::_key_initialized = true;
|
383 kumpf 1.81 }
384 else
385 {
|
386 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
387 mike 1.91 "Thread: ERROR - unable to create a thread key");
388 Thread::_key_error = true;
389 return -1;
|
390 kumpf 1.81 }
|
391 konrad.r 1.67 }
|
392 kumpf 1.81
393 PEG_METHOD_EXIT();
|
394 mike 1.91 return 0;
|
395 konrad.r 1.67 }
|
396 mday 1.19
|
397 mike 1.91 Thread *Thread::getCurrent()
|
398 mday 1.19 {
|
399 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getCurrent");
400 if (Thread::initializeKey() != 0)
401 {
402 return NULL;
403 }
|
404 kumpf 1.81 PEG_METHOD_EXIT();
|
405 mike 1.91 return (Thread *) TSDKey::get_thread_specific(_platform_thread_key);
|
406 mday 1.19 }
407
|
408 mike 1.91 void Thread::setCurrent(Thread * thrd)
|
409 mday 1.19 {
|
410 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setCurrent");
411 if (Thread::initializeKey() == 0)
|
412 kumpf 1.81 {
|
413 mike 1.91 if (TSDKey::
414 set_thread_specific(Thread::_platform_thread_key,
415 (void *) thrd) == 0)
416 {
|
417 marek 1.99 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL4,
|
418 mike 1.91 "Successful set Thread * into thread specific storage");
419 }
420 else
421 {
|
422 marek 1.106 PEG_TRACE_CSTRING(TRC_THREAD, Tracer::LEVEL1,
|
423 mike 1.91 "ERROR: error setting Thread * into thread specific storage");
424 }
|
425 kumpf 1.81 }
|
426 mike 1.91 PEG_METHOD_EXIT();
|
427 mday 1.19 }
428
|
429 mike 1.91 AcceptLanguageList *Thread::getLanguages()
|
430 mday 1.19 {
|
431 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getLanguages");
432
433 Thread *curThrd = Thread::getCurrent();
434 if (curThrd == NULL)
435 return NULL;
436 AcceptLanguageList *acceptLangs =
437 (AcceptLanguageList *) curThrd->reference_tsd("acceptLanguages");
438 curThrd->dereference_tsd();
439 PEG_METHOD_EXIT();
440 return acceptLangs;
|
441 mday 1.19 }
442
|
443 kumpf 1.102 void Thread::setLanguages(const AcceptLanguageList& langs)
|
444 mday 1.19 {
|
445 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setLanguages");
|
446 kumpf 1.81
|
447 mike 1.91 Thread *currentThrd = Thread::getCurrent();
448 if (currentThrd != NULL)
|
449 kumpf 1.81 {
|
450 kumpf 1.102 AutoPtr<AcceptLanguageList> langsCopy(new AcceptLanguageList(langs));
451
|
452 mike 1.91 // deletes the old tsd and creates a new one
|
453 kumpf 1.102 currentThrd->put_tsd(
454 "acceptLanguages",
455 language_delete,
456 sizeof (AcceptLanguageList *),
457 langsCopy.get());
458
459 langsCopy.release();
|
460 kumpf 1.81 }
461
462 PEG_METHOD_EXIT();
|
463 mday 1.19 }
|
464 mike 1.2
|
465 kumpf 1.98 void Thread::clearLanguages()
|
466 kumpf 1.81 {
|
467 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::clearLanguages");
468
469 Thread *currentThrd = Thread::getCurrent();
470 if (currentThrd != NULL)
|
471 kumpf 1.81 {
|
472 mike 1.91 // deletes the old tsd
473 currentThrd->delete_tsd("acceptLanguages");
|
474 kumpf 1.81 }
475
|
476 mike 1.91 PEG_METHOD_EXIT();
|
477 kumpf 1.81 }
|
478 mike 1.2
|
479 mike 1.91 // ATTN: not sure where to put this!
480 #ifdef PEGASUS_ZOS_SECURITY
481 bool isEnhancedSecurity = 99;
482 #endif
483
|
484 mike 1.2 PEGASUS_NAMESPACE_END
|