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