(file) Return to Thread.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

  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 mike  1.91 Boolean Thread::is_cancelled(void)
 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 mike  1.91 void Thread::join(void)
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 mike  1.91 void Thread::thread_init(void)
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 mike  1.91 void Thread::detach(void)
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 mike  1.91     // On Linux distributions released prior 2005, the implementation of 
158                // Native POSIX Thread Library returns ENOMEM instead of EAGAIN when
159                // there 
160                // 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 mike         1.91 Thread::Thread(ThreadReturnType(PEGASUS_THREAD_CDECL * start) (void *), void *parameter, Boolean detached):_is_detached(detached),
212                   _cancel_enabled(true),
213                   _cancelled(false),
214                   _start(start), _cleanup(), _tsd(), _thread_parm(parameter), _exit_code(0)
215                   {
216                       Threads::clear(_handle.thid);
217 kumpf        1.81 }
218 mday         1.20 
219 mike         1.91 Thread::~Thread()
220 mday         1.20 {
221 kumpf        1.81     try
222                       {
223 mike         1.91         join();
224                           empty_tsd();
225 kumpf        1.81     }
226 mike         1.91     catch(...)
227 kumpf        1.81     {
228 mike         1.91         // Do not allow the destructor to throw an exception
229 kumpf        1.81     }
230 mday         1.20 }
231                   
232 mike         1.91 #endif /* PEGASUS_HAVE_PTHREADS */
233                   
234                   //==============================================================================
235                   //
236                   // Windows Threads Implementation:
237                   //
238                   //==============================================================================
239 kumpf        1.81 
240 mike         1.91 #if defined(PEGASUS_HAVE_WINDOWS_THREADS)
241 kumpf        1.81 
242 mike         1.91 ThreadStatus Thread::run(void)
243                   {
244                       // Note: A Win32 thread ID is not the same thing as a pthread ID.
245                       // Win32 threads have both a thread ID and a handle.  The handle
246                       // is used in the wait functions, etc.
247                       // So _handle.thid is actually the thread handle.
248 kumpf        1.81 
249 mike         1.91     unsigned threadid = 0;
250 mike         1.2  
251 mike         1.91     ThreadType tt;
252                       tt.handle = (HANDLE) _beginthreadex(NULL, 0, _start, this, 0, &threadid);
253                       _handle.thid = tt;
254 chuck        1.39 
255 mike         1.95     if (Threads::null(_handle.thid))
256 mike         1.91     {
257                           if (errno == EAGAIN)
258 kumpf        1.81         {
259 mike         1.91             return PEGASUS_THREAD_INSUFFICIENT_RESOURCES;
260 kumpf        1.81         }
261 mike         1.91         else
262 kumpf        1.81         {
263 mike         1.91             return PEGASUS_THREAD_SETUP_FAILURE;
264 kumpf        1.81         }
265 mike         1.91     }
266                       return PEGASUS_THREAD_OK;
267                   }
268 mday         1.52 
269 mike         1.91 void Thread::cancel(void)
270                   {
271                       _cancelled = true;
272                   }
273 kumpf        1.82 
274 mike         1.91 void Thread::test_cancel(void)
275                   {
276                       if (_cancel_enabled && _cancelled)
277                       {
278                           exit_self(0);
279                       }
280                   }
281 kumpf        1.82 
282 mike         1.91 Boolean Thread::is_cancelled(void)
283                   {
284                       return _cancelled;
285                   }
286 kumpf        1.82 
287 mike         1.91 void Thread::thread_switch(void)
288                   {
289                       Sleep(0);
290                   }
291 kumpf        1.82 
292 mike         1.91 void Thread::sleep(Uint32 milliseconds)
293                   {
294                       Sleep(milliseconds);
295                   }
296 mike         1.2  
297 mike         1.91 void Thread::join(void)
298                   {
299 mike         1.95     if (!Threads::null(_handle.thid))
300 mike         1.91     {
301                           if (!_is_detached)
302                           {
303                               if (!_cancelled)
304 kumpf        1.82             {
305 mike         1.91                 // Emulate the unix join api. Caller sleeps until thread is
306                                   // done.
307                                   WaitForSingleObject(_handle.thid.handle, INFINITE);
308 kumpf        1.82             }
309 mike         1.91             else
310 kumpf        1.82             {
311 mike         1.91                 // Currently this is the only way to ensure this code does
312                                   // not 
313                                   // hang forever.
314                                   if (WaitForSingleObject(_handle.thid.handle, 10000) ==
315                                       WAIT_TIMEOUT)
316 kumpf        1.82                 {
317 mike         1.91                     TerminateThread(_handle.thid.handle, 0);
318 kumpf        1.82                 }
319 mike         1.91             }
320 s.hills      1.49 
321 mike         1.91             DWORD exit_code = 0;
322                               GetExitCodeThread(_handle.thid.handle, &exit_code);
323                               _exit_code = (ThreadReturnType) exit_code;
324 kumpf        1.81         }
325 mike         1.91 
326                           CloseHandle(_handle.thid.handle);
327                           Threads::clear(_handle.thid);
328 kumpf        1.82     }
329 mike         1.91 }
330 kumpf        1.14 
331 mike         1.91 void Thread::thread_init(void)
332                   {
333                       _cancel_enabled = true;
334 mike         1.2  }
335                   
336 mike         1.91 void Thread::detach(void)
337 mike         1.2  {
338 mike         1.91     _is_detached = true;
339                   }
340 kumpf        1.81 
341 mike         1.91 Thread::Thread(ThreadReturnType(PEGASUS_THREAD_CDECL * start) (void *),
342                                  void *parameter,
343                                  Boolean detached):_is_detached(detached),
344                   _cancel_enabled(true),
345                   _cancelled(false),
346                   _start(start), _cleanup(), _tsd(), _thread_parm(parameter), _exit_code(0)
347                   {
348                       Threads::clear(_handle.thid);
349                   }
350 kumpf        1.81 
351 mike         1.91 Thread::~Thread()
352                   {
353 kumpf        1.81     try
354                       {
355 mike         1.91         join();
356                           empty_tsd();
357                       }
358                       catch(...)
359                       {
360                       }
361                   }
362 kumpf        1.81 
363 mike         1.91 #endif /* PEGASUS_HAVE_WINDOWS_THREADS */
364 kumpf        1.57 
365 mike         1.91 //==============================================================================
366                   //
367                   // Common implementation:
368                   //
369                   //==============================================================================
370 kumpf        1.81 
371 mike         1.91 void thread_data::default_delete(void *data)
372                   {
373                       if (data != NULL)
374                           ::operator  delete(data);
375                   }
376 mike         1.2  
377 mike         1.91 void language_delete(void *data)
378                   {
379                       if (data != NULL)
380                       {
381                           AutoPtr < AcceptLanguageList > al(static_cast <
382                                                             AcceptLanguageList * >(data));
383 kumpf        1.57     }
384 mike         1.2  }
385                   
386 mike         1.91 Boolean Thread::_signals_blocked = false;
387                   #ifndef PEGASUS_OS_ZOS
388                   TSDKeyType Thread::_platform_thread_key = TSDKeyType(-1);
389                   #else
390                   TSDKeyType Thread::_platform_thread_key;
391                   #endif
392                   Boolean Thread::_key_initialized = false;
393                   Boolean Thread::_key_error = false;
394 mday         1.12 
395 mike         1.91 void Thread::cleanup_push(void (*routine) (void *), void *parm)
396 mike         1.2  {
397 mike         1.91     AutoPtr < cleanup_handler > cu(new cleanup_handler(routine, parm));
398                       _cleanup.insert_front(cu.get());
399                       cu.release();
400                       return;
401                   }
402 kumpf        1.81 
403 mike         1.91 void Thread::cleanup_pop(Boolean execute)
404                   {
405                       AutoPtr < cleanup_handler > cu;
406                       try
407                       {
408                           cu.reset(_cleanup.remove_front());
409                       }
410                       catch(IPCException &)
411                       {
412                           PEGASUS_ASSERT(0);
413                       }
414                       if (execute == true)
415                           cu->execute();
416                   }
417 kumpf        1.81 
418                   
419 mike         1.91 //thread_data *Thread::put_tsd(const Sint8 *key, void (*delete_func)(void *), Uint32 size, void *value)
420 kumpf        1.81 
421                   
422 mike         1.91 void Thread::exit_self(ThreadReturnType exit_code)
423                   {
424                   #if defined(PEGASUS_PLATFORM_HPUX_ACC) || \
425                       defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
426                       // NOTE: pthread_exit exhibits unusual behavior on RHEL 3 U2, as
427                       // documented in Bugzilla 3836.  Where feasible, it may be advantageous
428                       // to avoid using this function.
429                       pthread_exit(exit_code);
430                   #else
431                       // execute the cleanup stack and then return
432                       while (_cleanup.size())
433                       {
434 kumpf        1.81         try
435                           {
436 mike         1.91             cleanup_pop(true);
437 kumpf        1.81         }
438 mike         1.91         catch(IPCException &)
439 kumpf        1.81         {
440 mike         1.91             PEGASUS_ASSERT(0);
441 kumpf        1.81             break;
442                           }
443 mike         1.91     }
444                       _exit_code = exit_code;
445                       Threads::exit(exit_code);
446                       Threads::clear(_handle.thid);
447                   #endif
448                   }
449 kumpf        1.81 
450 mike         1.91 Sint8 Thread::initializeKey()
451                   {
452                       PEG_METHOD_ENTER(TRC_THREAD, "Thread::initializeKey");
453                       if (!Thread::_key_initialized)
454                       {
455                           if (Thread::_key_error)
456                           {
457                               Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
458                                             "Thread: ERROR - thread key error");
459                               return -1;
460                           }
461 kumpf        1.81 
462 mike         1.91         if (TSDKey::create(&Thread::_platform_thread_key) == 0)
463 kumpf        1.81         {
464 mike         1.91             Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
465                                             "Thread: able to create a thread key");
466                               Thread::_key_initialized = true;
467 kumpf        1.81         }
468                           else
469                           {
470 mike         1.91             Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
471                                             "Thread: ERROR - unable to create a thread key");
472                               Thread::_key_error = true;
473                               return -1;
474 kumpf        1.81         }
475 konrad.r     1.67     }
476 kumpf        1.81 
477                       PEG_METHOD_EXIT();
478 mike         1.91     return 0;
479 konrad.r     1.67 }
480 mday         1.19 
481 mike         1.91 Thread *Thread::getCurrent()
482 mday         1.19 {
483 mike         1.91     PEG_METHOD_ENTER(TRC_THREAD, "Thread::getCurrent");
484                       if (Thread::initializeKey() != 0)
485                       {
486                           return NULL;
487                       }
488 kumpf        1.81     PEG_METHOD_EXIT();
489 mike         1.91     return (Thread *) TSDKey::get_thread_specific(_platform_thread_key);
490 mday         1.19 }
491                   
492 mike         1.91 void Thread::setCurrent(Thread * thrd)
493 mday         1.19 {
494 mike         1.91     PEG_METHOD_ENTER(TRC_THREAD, "Thread::setCurrent");
495                       if (Thread::initializeKey() == 0)
496 kumpf        1.81     {
497 mike         1.91         if (TSDKey::
498                               set_thread_specific(Thread::_platform_thread_key,
499                                                   (void *) thrd) == 0)
500                           {
501                               Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
502                                   "Successful set Thread * into thread specific storage");
503                           }
504                           else
505                           {
506                               Tracer::trace(TRC_THREAD, Tracer::LEVEL4,
507                                   "ERROR: error setting Thread * into thread specific storage");
508                           }
509 kumpf        1.81     }
510 mike         1.91     PEG_METHOD_EXIT();
511 mday         1.19 }
512                   
513 mike         1.91 AcceptLanguageList *Thread::getLanguages()
514 mday         1.19 {
515 mike         1.91     PEG_METHOD_ENTER(TRC_THREAD, "Thread::getLanguages");
516                   
517                       Thread *curThrd = Thread::getCurrent();
518                       if (curThrd == NULL)
519                           return NULL;
520                       AcceptLanguageList *acceptLangs =
521                           (AcceptLanguageList *) curThrd->reference_tsd("acceptLanguages");
522                       curThrd->dereference_tsd();
523                       PEG_METHOD_EXIT();
524                       return acceptLangs;
525 mday         1.19 }
526                   
527 mike         1.91 void Thread::setLanguages(AcceptLanguageList * langs)   // l10n
528 mday         1.19 {
529 mike         1.91     PEG_METHOD_ENTER(TRC_THREAD, "Thread::setLanguages");
530 kumpf        1.81 
531 mike         1.91     Thread *currentThrd = Thread::getCurrent();
532                       if (currentThrd != NULL)
533 kumpf        1.81     {
534 mike         1.91         // deletes the old tsd and creates a new one
535                           currentThrd->put_tsd("acceptLanguages",
536                                                language_delete,
537                                                sizeof (AcceptLanguageList *), langs);
538 kumpf        1.81     }
539                   
540                       PEG_METHOD_EXIT();
541 mday         1.19 }
542 mike         1.2  
543 mike         1.91 void Thread::clearLanguages()   // l10n
544 kumpf        1.81 {
545 mike         1.91     PEG_METHOD_ENTER(TRC_THREAD, "Thread::clearLanguages");
546                   
547                       Thread *currentThrd = Thread::getCurrent();
548                       if (currentThrd != NULL)
549 kumpf        1.81     {
550 mike         1.91         // deletes the old tsd
551                           currentThrd->delete_tsd("acceptLanguages");
552 kumpf        1.81     }
553                   
554 mike         1.91     PEG_METHOD_EXIT();
555 kumpf        1.81 }
556 mike         1.2  
557 mike         1.91 // ATTN: not sure where to put this!
558                   #ifdef PEGASUS_ZOS_SECURITY
559                   bool isEnhancedSecurity = 99;
560                   #endif
561                   
562 mike         1.2  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2