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 // Author: Mike Day (mdday@us.ibm.com)
33 //
34 // Modified By: Rudy Schuet (rudy.schuet@compaq.com) 11/12/01
|
35 chip 1.11 // added nsk platform support
|
36 kumpf 1.59 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
37 a.arora 1.64 // Amit K Arora, IBM (amita@in.ibm.com) for PEP#101
|
38 gs.keenan 1.76 // Sean Keenan, Hewlett-Packard Company (sean.keenan@hp.com)
|
39 david.dillard 1.83 // David Dillard, VERITAS Software Corp.
40 // (david.dillard@veritas.com)
|
41 mike 1.2 //
42 //%/////////////////////////////////////////////////////////////////////////////
43
44 #include "Thread.h"
|
45 kumpf 1.68 #include <exception>
|
46 kumpf 1.14 #include <Pegasus/Common/Tracer.h>
|
47 mike 1.91 #include "Time.h"
|
48 mike 1.2
|
49 mike 1.91 PEGASUS_USING_STD;
|
50 mike 1.2
51 PEGASUS_NAMESPACE_BEGIN
52
|
53 mike 1.91 //==============================================================================
54 //
55 // POSIX Threads Implementation:
56 //
57 //==============================================================================
|
58 mday 1.42
|
59 mike 1.91 #if defined(PEGASUS_HAVE_PTHREADS)
60
61 struct StartWrapperArg
|
62 chip 1.11 {
|
63 mike 1.91 void *(PEGASUS_THREAD_CDECL * start) (void *);
64 void *arg;
65 };
|
66 mike 1.2
|
67 mike 1.91 extern "C" void *_start_wrapper(void *arg_)
|
68 chuck 1.43 {
|
69 mike 1.91 StartWrapperArg *arg = (StartWrapperArg *) arg_;
|
70 chuck 1.43
|
71 mike 1.91 void *return_value = (*arg->start) (arg->arg);
72 delete arg;
|
73 chuck 1.37
|
74 mike 1.91 return return_value;
75 }
|
76 mike 1.2
|
77 mike 1.91 void Thread::cancel()
|
78 mike 1.2 {
|
79 mike 1.91 _cancelled = true;
80 pthread_cancel(_handle.thid.tt_handle());
|
81 mike 1.2 }
|
82 kumpf 1.81
|
83 mike 1.91 void Thread::test_cancel()
|
84 mike 1.2 {
|
85 mike 1.91 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
86 pthread_testintr();
87 #else
88 pthread_testcancel();
89 #endif
|
90 mike 1.2 }
|
91 kumpf 1.81
|
92 mike 1.91 Boolean Thread::is_cancelled(void)
|
93 chip 1.11 {
|
94 mike 1.91 return _cancelled;
|
95 mike 1.2 }
96
|
97 mike 1.91 void Thread::thread_switch()
98 {
99 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
100 pthread_yield(NULL);
101 #else
102 sched_yield();
|
103 mike 1.2 #endif
|
104 mike 1.91 }
|
105 mike 1.2
|
106 mike 1.91 /*
107 ATTN: why are these missing on other platforms?
108 */
109 #if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
110 void Thread::suspend()
|
111 chuck 1.39 {
|
112 mike 1.91 pthread_kill(_handle.thid.tt_handle(), SIGSTOP);
|
113 chuck 1.39 }
114
|
115 mike 1.91 void Thread::resume()
|
116 chuck 1.37 {
|
117 mike 1.91 pthread_kill(_handle.thid.tt_handle(), SIGCONT);
|
118 chuck 1.39 }
|
119 mike 1.91 #endif
|
120 chuck 1.39
|
121 mike 1.91 void Thread::sleep(Uint32 msec)
|
122 chuck 1.39 {
|
123 mike 1.91 Threads::sleep(msec);
|
124 chuck 1.37 }
125
|
126 mike 1.91 void Thread::join(void)
|
127 chuck 1.37 {
|
128 mike 1.91 if (!_is_detached && Threads::id(_handle.thid) != 0)
129 pthread_join(_handle.thid.tt_handle(), &_exit_code);
|
130 kumpf 1.81
|
131 mike 1.91 Threads::clear(_handle.thid);
|
132 chuck 1.37 }
133
|
134 mike 1.91 void Thread::thread_init(void)
|
135 chuck 1.37 {
|
136 mike 1.91 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
137 pthread_setintr(PTHREAD_INTR_ENABLE);
138 pthread_setintrtype(PTHREAD_INTR_ASYNCHRONOUS);
139 #else
140 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
141 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
142 #endif
143 _cancel_enabled = true;
|
144 chuck 1.37 }
145
|
146 mike 1.91 void Thread::detach(void)
|
147 chuck 1.37 {
|
148 mike 1.91 _is_detached = true;
149 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
150 pthread_t thread_id=_handle.thid.tt_handle();
151 pthread_detach(&thread_id);
152 #else
153 pthread_detach(_handle.thid.tt_handle());
154 #endif
|
155 chuck 1.37 }
156
|
157 mike 1.91 ThreadStatus Thread::run()
158 {
159 StartWrapperArg *arg = new StartWrapperArg;
160 arg->start = _start;
161 arg->arg = this;
|
162 mday 1.52
|
163 mike 1.91 Threads::Type type = _is_detached ? Threads::DETACHED : Threads::JOINABLE;
164 int rc = Threads::create(_handle.thid, type, _start_wrapper, arg);
|
165 kumpf 1.81
|
166 mike 1.91 // On Linux distributions released prior 2005, the implementation of
167 // Native POSIX Thread Library returns ENOMEM instead of EAGAIN when
168 // there
169 // are no insufficient memory. Hence we are checking for both. See bug
170 // 386.
|
171 mday 1.58
|
172 mike 1.91 if ((rc == EAGAIN) || (rc == ENOMEM))
|
173 kumpf 1.81 {
|
174 mike 1.91 Threads::clear(_handle.thid);
175 delete arg;
176 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
177 kumpf 1.81 }
|
178 mike 1.91 else if (rc != 0)
|
179 kumpf 1.81 {
|
180 mike 1.91 Threads::clear(_handle.thid);
181 delete arg;
182 return PEGASUS_THREAD_SETUP_FAILURE;
|
183 kumpf 1.81 }
|
184 mike 1.91 return PEGASUS_THREAD_OK;
185 }
|
186 mday 1.58
|
187 mike 1.91 static sigset_t *block_signal_mask(sigset_t * sig)
188 {
189 sigemptyset(sig);
190 // should not be used for main()
191 sigaddset(sig, SIGHUP);
192 sigaddset(sig, SIGINT);
193 // maybe useless, since KILL can't be blocked according to POSIX
194 sigaddset(sig, SIGKILL);
195
196 sigaddset(sig, SIGABRT);
197 sigaddset(sig, SIGALRM);
198 sigaddset(sig, SIGPIPE);
199
200
201 // Note: older versions of the linux pthreads library use SIGUSR1 and SIGUSR2
202 // internally to stop and start threads that are blocking, the newer ones
203 // implement this through the kernel's real time signals
204 // since SIGSTOP/CONT can handle suspend()/resume() on Linux
205 // block them
206 // #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU)
207 // sigaddset(sig, SIGUSR1);
208 mike 1.91 // sigaddset(sig, SIGUSR2);
209 // #endif
210 #ifndef PEGASUS_PLATFORM_ZOS_ZSERIES_IBM
211 pthread_sigmask(SIG_BLOCK, sig, NULL);
212 #else
213 sigprocmask(SIG_BLOCK, sig, NULL);
214 #endif
215 return sig;
216 }
|
217 mday 1.52
|
218 mike 1.91 Thread::Thread(ThreadReturnType(PEGASUS_THREAD_CDECL * start) (void *), void *parameter, Boolean detached):_is_detached(detached),
219 _cancel_enabled(true),
220 _cancelled(false),
221 _start(start), _cleanup(), _tsd(), _thread_parm(parameter), _exit_code(0)
222 {
223 Threads::clear(_handle.thid);
|
224 kumpf 1.81 }
|
225 mday 1.20
|
226 mike 1.91 Thread::~Thread()
|
227 mday 1.20 {
|
228 kumpf 1.81 try
229 {
|
230 mike 1.91 join();
231 empty_tsd();
|
232 kumpf 1.81 }
|
233 mike 1.91 catch(...)
|
234 kumpf 1.81 {
|
235 mike 1.91 // Do not allow the destructor to throw an exception
|
236 kumpf 1.81 }
|
237 mday 1.20 }
238
|
239 mike 1.91 #endif /* PEGASUS_HAVE_PTHREADS */
240
241 //==============================================================================
242 //
243 // Windows Threads Implementation:
244 //
245 //==============================================================================
|
246 kumpf 1.81
|
247 mike 1.91 #if defined(PEGASUS_HAVE_WINDOWS_THREADS)
|
248 kumpf 1.81
|
249 mike 1.91 ThreadStatus Thread::run(void)
250 {
251 // Note: A Win32 thread ID is not the same thing as a pthread ID.
252 // Win32 threads have both a thread ID and a handle. The handle
253 // is used in the wait functions, etc.
254 // So _handle.thid is actually the thread handle.
|
255 kumpf 1.81
|
256 mike 1.91 unsigned threadid = 0;
|
257 mike 1.2
|
258 mike 1.91 ThreadType tt;
259 tt.handle = (HANDLE) _beginthreadex(NULL, 0, _start, this, 0, &threadid);
260 _handle.thid = tt;
|
261 chuck 1.39
|
262 mike 1.91 if (Threads::id(_handle.thid) == 0)
263 {
264 if (errno == EAGAIN)
|
265 kumpf 1.81 {
|
266 mike 1.91 return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
|
267 kumpf 1.81 }
|
268 mike 1.91 else
|
269 kumpf 1.81 {
|
270 mike 1.91 return PEGASUS_THREAD_SETUP_FAILURE;
|
271 kumpf 1.81 }
|
272 mike 1.91 }
273 return PEGASUS_THREAD_OK;
274 }
|
275 mday 1.52
|
276 mike 1.91 void Thread::cancel(void)
277 {
278 _cancelled = true;
279 }
|
280 kumpf 1.82
|
281 mike 1.91 void Thread::test_cancel(void)
282 {
283 if (_cancel_enabled && _cancelled)
284 {
285 exit_self(0);
286 }
287 }
|
288 kumpf 1.82
|
289 mike 1.91 Boolean Thread::is_cancelled(void)
290 {
291 return _cancelled;
292 }
|
293 kumpf 1.82
|
294 mike 1.91 void Thread::thread_switch(void)
295 {
296 Sleep(0);
297 }
|
298 kumpf 1.82
|
299 mike 1.91 void Thread::sleep(Uint32 milliseconds)
300 {
301 Sleep(milliseconds);
302 }
|
303 mike 1.2
|
304 mike 1.91 void Thread::join(void)
305 {
306 if (Threads::id(_handle.thid) != 0)
307 {
308 if (!_is_detached)
309 {
310 if (!_cancelled)
|
311 kumpf 1.82 {
|
312 mike 1.91 // Emulate the unix join api. Caller sleeps until thread is
313 // done.
314 WaitForSingleObject(_handle.thid.handle, INFINITE);
|
315 kumpf 1.82 }
|
316 mike 1.91 else
|
317 kumpf 1.82 {
|
318 mike 1.91 // Currently this is the only way to ensure this code does
319 // not
320 // hang forever.
321 if (WaitForSingleObject(_handle.thid.handle, 10000) ==
322 WAIT_TIMEOUT)
|
323 kumpf 1.82 {
|
324 mike 1.91 TerminateThread(_handle.thid.handle, 0);
|
325 kumpf 1.82 }
|
326 mike 1.91 }
|
327 s.hills 1.49
|
328 mike 1.91 DWORD exit_code = 0;
329 GetExitCodeThread(_handle.thid.handle, &exit_code);
330 _exit_code = (ThreadReturnType) exit_code;
|
331 kumpf 1.81 }
|
332 mike 1.91
333 CloseHandle(_handle.thid.handle);
334 Threads::clear(_handle.thid);
|
335 kumpf 1.82 }
|
336 mike 1.91 }
|
337 kumpf 1.14
|
338 mike 1.91 void Thread::thread_init(void)
339 {
340 _cancel_enabled = true;
|
341 mike 1.2 }
342
|
343 mike 1.91 void Thread::detach(void)
|
344 mike 1.2 {
|
345 mike 1.91 _is_detached = true;
346 }
|
347 kumpf 1.81
|
348 mike 1.91 Thread::Thread(ThreadReturnType(PEGASUS_THREAD_CDECL * start) (void *),
349 void *parameter,
350 Boolean detached):_is_detached(detached),
351 _cancel_enabled(true),
352 _cancelled(false),
353 _start(start), _cleanup(), _tsd(), _thread_parm(parameter), _exit_code(0)
354 {
355 Threads::clear(_handle.thid);
356 }
|
357 kumpf 1.81
|
358 mike 1.91 Thread::~Thread()
359 {
|
360 kumpf 1.81 try
361 {
|
362 mike 1.91 join();
363 empty_tsd();
364 }
365 catch(...)
366 {
367 }
368 }
|
369 kumpf 1.81
|
370 mike 1.91 #endif /* PEGASUS_HAVE_WINDOWS_THREADS */
|
371 kumpf 1.57
|
372 mike 1.91 //==============================================================================
373 //
374 // Common implementation:
375 //
376 //==============================================================================
|
377 kumpf 1.81
|
378 mike 1.91 void thread_data::default_delete(void *data)
379 {
380 if (data != NULL)
381 ::operator delete(data);
382 }
|
383 mike 1.2
|
384 mike 1.91 void language_delete(void *data)
385 {
386 if (data != NULL)
387 {
388 AutoPtr < AcceptLanguageList > al(static_cast <
389 AcceptLanguageList * >(data));
|
390 kumpf 1.57 }
|
391 mike 1.2 }
392
|
393 mike 1.91 Boolean Thread::_signals_blocked = false;
394 #ifndef PEGASUS_OS_ZOS
395 TSDKeyType Thread::_platform_thread_key = TSDKeyType(-1);
396 #else
397 TSDKeyType Thread::_platform_thread_key;
398 #endif
399 Boolean Thread::_key_initialized = false;
400 Boolean Thread::_key_error = false;
|
401 mday 1.12
|
402 mike 1.91 void Thread::cleanup_push(void (*routine) (void *), void *parm)
|
403 mike 1.2 {
|
404 mike 1.91 AutoPtr < cleanup_handler > cu(new cleanup_handler(routine, parm));
405 _cleanup.insert_front(cu.get());
406 cu.release();
407 return;
408 }
|
409 kumpf 1.81
|
410 mike 1.91 void Thread::cleanup_pop(Boolean execute)
411 {
412 AutoPtr < cleanup_handler > cu;
413 try
414 {
415 cu.reset(_cleanup.remove_front());
416 }
417 catch(IPCException &)
418 {
419 PEGASUS_ASSERT(0);
420 }
421 if (execute == true)
422 cu->execute();
423 }
|
424 kumpf 1.81
425
|
426 mike 1.91 //thread_data *Thread::put_tsd(const Sint8 *key, void (*delete_func)(void *), Uint32 size, void *value)
|
427 kumpf 1.81
428
|
429 mike 1.91 void Thread::exit_self(ThreadReturnType exit_code)
430 {
431 #if defined(PEGASUS_PLATFORM_HPUX_ACC) || \
432 defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
433 // NOTE: pthread_exit exhibits unusual behavior on RHEL 3 U2, as
434 // documented in Bugzilla 3836. Where feasible, it may be advantageous
435 // to avoid using this function.
436 pthread_exit(exit_code);
437 #else
438 // execute the cleanup stack and then return
439 while (_cleanup.size())
440 {
|
441 kumpf 1.81 try
442 {
|
443 mike 1.91 cleanup_pop(true);
|
444 kumpf 1.81 }
|
445 mike 1.91 catch(IPCException &)
|
446 kumpf 1.81 {
|
447 mike 1.91 PEGASUS_ASSERT(0);
|
448 kumpf 1.81 break;
449 }
|
450 mike 1.91 }
451 _exit_code = exit_code;
452 Threads::exit(exit_code);
453 Threads::clear(_handle.thid);
454 #endif
455 }
|
456 kumpf 1.81
|
457 mike 1.91 Sint8 Thread::initializeKey()
458 {
459 PEG_METHOD_ENTER(TRC_THREAD, "Thread::initializeKey");
460 if (!Thread::_key_initialized)
461 {
462 if (Thread::_key_error)
463 {
464 Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
465 "Thread: ERROR - thread key error");
466 return -1;
467 }
|
468 kumpf 1.81
|
469 mike 1.91 if (TSDKey::create(&Thread::_platform_thread_key) == 0)
|
470 kumpf 1.81 {
|
471 mike 1.91 Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
472 "Thread: able to create a thread key");
473 Thread::_key_initialized = true;
|
474 kumpf 1.81 }
475 else
476 {
|
477 mike 1.91 Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
478 "Thread: ERROR - unable to create a thread key");
479 Thread::_key_error = true;
480 return -1;
|
481 kumpf 1.81 }
|
482 konrad.r 1.67 }
|
483 kumpf 1.81
484 PEG_METHOD_EXIT();
|
485 mike 1.91 return 0;
|
486 konrad.r 1.67 }
|
487 mday 1.19
|
488 mike 1.91 Thread *Thread::getCurrent()
|
489 mday 1.19 {
|
490 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getCurrent");
491 if (Thread::initializeKey() != 0)
492 {
493 return NULL;
494 }
|
495 kumpf 1.81 PEG_METHOD_EXIT();
|
496 mike 1.91 return (Thread *) TSDKey::get_thread_specific(_platform_thread_key);
|
497 mday 1.19 }
498
|
499 mike 1.91 void Thread::setCurrent(Thread * thrd)
|
500 mday 1.19 {
|
501 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setCurrent");
502 if (Thread::initializeKey() == 0)
|
503 kumpf 1.81 {
|
504 mike 1.91 if (TSDKey::
505 set_thread_specific(Thread::_platform_thread_key,
506 (void *) thrd) == 0)
507 {
508 Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
509 "Successful set Thread * into thread specific storage");
510 }
511 else
512 {
513 Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
514 "ERROR: error setting Thread * into thread specific storage");
515 }
|
516 kumpf 1.81 }
|
517 mike 1.91 PEG_METHOD_EXIT();
|
518 mday 1.19 }
519
|
520 mike 1.91 AcceptLanguageList *Thread::getLanguages()
|
521 mday 1.19 {
|
522 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::getLanguages");
523
524 Thread *curThrd = Thread::getCurrent();
525 if (curThrd == NULL)
526 return NULL;
527 AcceptLanguageList *acceptLangs =
528 (AcceptLanguageList *) curThrd->reference_tsd("acceptLanguages");
529 curThrd->dereference_tsd();
530 PEG_METHOD_EXIT();
531 return acceptLangs;
|
532 mday 1.19 }
533
|
534 mike 1.91 void Thread::setLanguages(AcceptLanguageList * langs) // l10n
|
535 mday 1.19 {
|
536 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::setLanguages");
|
537 kumpf 1.81
|
538 mike 1.91 Thread *currentThrd = Thread::getCurrent();
539 if (currentThrd != NULL)
|
540 kumpf 1.81 {
|
541 mike 1.91 // deletes the old tsd and creates a new one
542 currentThrd->put_tsd("acceptLanguages",
543 language_delete,
544 sizeof (AcceptLanguageList *), langs);
|
545 kumpf 1.81 }
546
547 PEG_METHOD_EXIT();
|
548 mday 1.19 }
|
549 mike 1.2
|
550 mike 1.91 void Thread::clearLanguages() // l10n
|
551 kumpf 1.81 {
|
552 mike 1.91 PEG_METHOD_ENTER(TRC_THREAD, "Thread::clearLanguages");
553
554 Thread *currentThrd = Thread::getCurrent();
555 if (currentThrd != NULL)
|
556 kumpf 1.81 {
|
557 mike 1.91 // deletes the old tsd
558 currentThrd->delete_tsd("acceptLanguages");
|
559 kumpf 1.81 }
560
|
561 mike 1.91 PEG_METHOD_EXIT();
|
562 kumpf 1.81 }
|
563 mike 1.2
|
564 mike 1.91 // ATTN: not sure where to put this!
565 #ifdef PEGASUS_ZOS_SECURITY
566 bool isEnhancedSecurity = 99;
567 #endif
568
|
569 mike 1.2 PEGASUS_NAMESPACE_END
|