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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2