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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2