(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            // 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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2