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