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

  1 karl  1.55 //%2006////////////////////////////////////////////////////////////////////////
  2 mike  1.2  //
  3 karl  1.42 // 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.34 // IBM Corp.; EMC Corporation, The Open Group.
  7 karl  1.42 // 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.44 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11 karl  1.55 // 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 kumpf 1.18 // 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            // 
 21 kumpf 1.18 // 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 kumpf 1.18 // 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            #ifndef Pegasus_Thread_h
 35            #define Pegasus_Thread_h
 36 kumpf 1.26 
 37            #include <cstring>
 38 mike  1.2  #include <Pegasus/Common/Config.h>
 39 mike  1.58 #include <Pegasus/Common/AtomicInt.h>
 40 kumpf 1.23 #include <Pegasus/Common/InternalException.h>
 41 kumpf 1.54 #include <Pegasus/Common/AcceptLanguageList.h>
 42 kumpf 1.22 #include <Pegasus/Common/Linkage.h>
 43 a.arora 1.37 #include <Pegasus/Common/AutoPtr.h>
 44 mike    1.56 #include <Pegasus/Common/List.h>
 45 mike    1.58 #include <Pegasus/Common/Mutex.h>
 46              #include <Pegasus/Common/Semaphore.h>
 47              #include <Pegasus/Common/TSDKey.h>
 48              #include <Pegasus/Common/Threads.h>
 49 mike    1.2  
 50 mike    1.58 #if defined(PEGASUS_HAVE_PTHREADS)
 51              # include <signal.h>
 52              #endif
 53              
 54 kumpf   1.59 PEGASUS_NAMESPACE_BEGIN
 55 mike    1.2  
 56 mike    1.56 class PEGASUS_COMMON_LINKAGE cleanup_handler : public Linkable
 57 mike    1.2  {
 58 mike    1.58 public:
 59                  cleanup_handler(void (*routine) (void *), void *arg):_routine(routine),
 60                      _arg(arg)
 61                  {
 62                  }
 63                  ~cleanup_handler()
 64                  {;
 65                  }
 66              
 67              private:
 68              
 69                  void execute()
 70                  {
 71                      _routine(_arg);
 72                  }
 73              
 74 kumpf   1.59     cleanup_handler();
 75              
 76 mike    1.58     void (*_routine)(void*);
 77                  void *_arg;
 78 mike    1.2  
 79 mike    1.58     friend class Thread;
 80 mike    1.2  };
 81              
 82              ///////////////////////////////////////////////////////////////////////////////
 83              
 84 mike    1.58 class PEGASUS_COMMON_LINKAGE thread_data : public Linkable
 85              {
 86              public:
 87              
 88                  static void default_delete(void *data);
 89              
 90                  thread_data(const char *key) : _delete_func(NULL), _data(NULL), _size(0)
 91                  {
 92                      PEGASUS_ASSERT(key != NULL);
 93                      size_t keysize = strlen(key);
 94                      _key.reset(new char[keysize + 1]);
 95                      memcpy(_key.get(), key, keysize);
 96                      _key.get()[keysize] = 0x00;
 97                  }
 98 mike    1.2  
 99 mike    1.58     thread_data(const char *key, size_t size) :
100                      _delete_func(default_delete), _size(size)
101                  {
102                      PEGASUS_ASSERT(key != NULL);
103                      size_t keysize = strlen(key);
104                      _key.reset(new char[keysize + 1]);
105                      memcpy(_key.get(), key, keysize);
106                      _key.get()[keysize] = 0x00;
107                      _data =::operator  new(_size);
108                  }
109 mike    1.2  
110 kumpf   1.59     thread_data(const char *key, size_t size, void *data)
111                      : _delete_func(default_delete), _size(size)
112 mike    1.58     {
113                      PEGASUS_ASSERT(key != NULL);
114                      PEGASUS_ASSERT(data != NULL);
115                      size_t keysize = strlen(key);
116              
117                      _key.reset(new char[keysize + 1]);
118                      memcpy(_key.get(), key, keysize);
119                      _key.get()[keysize] = 0x00;
120                      _data =::operator  new(_size);
121                      memcpy(_data, data, size);
122                  }
123 kumpf   1.48 
124 mike    1.58     ~thread_data()
125                  {
126                      if (_data != NULL)
127                          if (_delete_func != NULL)
128 sage    1.9              {
129 mike    1.58                 _delete_func(_data);
130 sage    1.9              }
131 mike    1.58     }
132 mike    1.2  
133 mike    1.58     /**
134                   * This function is used to put data in thread space.
135                   *
136                   * Be aware that there is NOTHING in place to stop
137                   * other users of the thread to remove this data.
138                   * Or change the data.
139                   *
140                   * You, the developer has to make sure that there are
141                   * no situations in which this can arise (ie, have a
142                   * lock for the function which manipulates the TSD.
143                   *
144                   * @exception NullPointer
145                  */
146 kumpf   1.59     void put_data(void (*del) (void *), size_t size, void* data)
147 mike    1.58     {
148                      if (_data != NULL)
149                          if (_delete_func != NULL)
150                              _delete_func(_data);
151              
152                      _delete_func = del;
153                      _data = data;
154                      _size = size;
155                      return;
156                  }
157 mike    1.2  
158 mike    1.58     size_t get_size()
159                  {
160                      return _size;
161                  }
162 mike    1.2  
163 kumpf   1.59     /**
164                      This function is used to retrieve data from the
165                      TSD, the thread specific data.
166              
167                      Be aware that there is NOTHING in place to stop
168                      other users of the thread to change the data you
169                      get from this function.
170              
171                      You, the developer has to make sure that there are
172                      no situations in which this can arise (ie, have a
173                      lock for the function which manipulates the TSD.
174                   */
175                  void get_data(void** data, size_t* size)
176 mike    1.58     {
177                      if (data == NULL || size == NULL)
178 kumpf   1.48             throw NullPointer();
179              
180 mike    1.58         *data = _data;
181                      *size = _size;
182                  }
183              
184                  // @exception NullPointer
185 kumpf   1.59     void copy_data(void** buf, size_t* size)
186 mike    1.58     {
187                      if ((buf == NULL) || (size == NULL))
188 david.dillard 1.50             throw NullPointer();
189 mike          1.58         *buf =::operator  new(_size);
190                            *size = _size;
191                            memcpy(*buf, _data, _size);
192                        }
193 mike          1.2  
194 kumpf         1.59     inline Boolean operator==(const void* key) const
195 mike          1.58     {
196                            if (!strcmp(_key.get(), reinterpret_cast < const char *>(key)))
197 kumpf         1.59             return true;
198                            return false;
199 mike          1.58     }
200                    
201 kumpf         1.59     inline Boolean operator==(const thread_data& b) const
202 mike          1.58     {
203 kumpf         1.59         return operator==(b._key.get());
204 mike          1.58     }
205                    
206 kumpf         1.59     static bool equal(const thread_data* node, const void* key)
207 mike          1.58     {
208                            return ((thread_data *) node)->operator==(key);
209                        }
210                    
211                      private:
212 kumpf         1.59     void (*_delete_func) (void* data);
213 mike          1.58     thread_data();
214 kumpf         1.59     void* _data;
215 mike          1.58     size_t _size;
216 kumpf         1.59     AutoArrayPtr<char> _key;
217 mike          1.58 
218                        friend class Thread;
219 mike          1.2  };
220                    
221                    
222 mike          1.58 enum ThreadStatus
223                    {
224                        PEGASUS_THREAD_OK = 1,      /* No problems */
225                        PEGASUS_THREAD_INSUFFICIENT_RESOURCES,      /* Can't allocate a thread.
226                                                                       Not enough memory. Try
227                                                                       again later */
228 kumpf         1.59     PEGASUS_THREAD_SETUP_FAILURE,       /* Could not allocate into the thread
229 mike          1.58                                            specific data storage. */
230                        PEGASUS_THREAD_UNAVAILABLE  /* Service is being destroyed and no new
231                                                       threads can be provided. */
232 konrad.r      1.53 };
233                    
234 mike          1.2  ///////////////////////////////////////////////////////////////////////////
235                    
236 kumpf         1.59 class PEGASUS_COMMON_LINKAGE Thread : public Linkable
237 mike          1.2  {
238 kumpf         1.59 public:
239 mike          1.2  
240 kumpf         1.59     Thread(
241                            ThreadReturnType(PEGASUS_THREAD_CDECL* start) (void*),
242                            void* parameter,
243                            Boolean detached);
244 mike          1.2  
245 mike          1.58      ~Thread();
246 mike          1.2  
247 mike          1.58       /** Start the thread.
248 kumpf         1.59           @return PEGASUS_THREAD_OK if the thread is started successfully,
249                              PEGASUS_THREAD_INSUFFICIENT_RESOURCES if the resources necessary
250                              to start the thread are not currently available.
251                              PEGASUS_THREAD_SETUP_FAILURE if the thread could not
252 mike          1.58           be create properly - check the 'errno' value for specific operating
253                              system return code.
254 kumpf         1.36        */
255 mike          1.58     ThreadStatus run();
256 mike          1.2  
257 mike          1.58     // get the user parameter
258                        inline void *get_parm()
259                        {
260                            return _thread_parm;
261                        }
262 mike          1.2  
263 mike          1.58     // cancellation must be deferred (not asynchronous)
264                        // for user-level threads the thread itself can decide
265                        // when it should die.
266                        void cancel();
267                    
268                        // cancel if there is a pending cancellation request
269                        void test_cancel();
270                    
271                        Boolean is_cancelled();
272                    
273                        // for user-level threads - put the calling thread
274                        // to sleep and jump to the thread scheduler.
275                        // platforms with preemptive scheduling and native threads
276                        // can define this to be a no-op.
277                        // platforms without preemptive scheduling like NetWare
278                        // or gnu portable threads will have an existing
279                        // routine that can be mapped to this method
280 mike          1.2  
281 mike          1.58     void thread_switch();
282 mike          1.2  
283 david.eger    1.27 #if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
284 mike          1.58     // suspend this thread
285                        void suspend();
286 mike          1.2  
287 mike          1.58     // resume this thread
288                        void resume();
289 mike          1.2  #endif
290                    
291 mike          1.58     static void sleep(Uint32 msec);
292 mike          1.2  
293 mike          1.58     // block the calling thread until this thread terminates
294                        void join();
295                        void thread_init();
296                    
297                        // thread routine needs to call this function when
298                        // it is ready to exit
299                        void exit_self(ThreadReturnType return_code);
300                    
301                        // stack of functions to be called when thread terminates
302                        // will be called last in first out (LIFO)
303                        // @exception IPCException
304 kumpf         1.59     void cleanup_push(void (*routine) (void *), void* parm);
305 mike          1.58 
306                        // @exception IPCException
307                        void cleanup_pop(Boolean execute = true);
308                    
309                        // create and initialize a tsd
310                        // @exception IPCException
311 kumpf         1.59     inline void create_tsd(const char* key, int size, void* buffer)
312 mike          1.58     {
313 kumpf         1.59         AutoPtr<thread_data> tsd(new thread_data(key, size, buffer));
314 mike          1.56         _tsd.insert_front(tsd.get());
315 a.arora       1.37         tsd.release();
316 mike          1.58     }
317 mike          1.2  
318 mike          1.58     // get the buffer associated with the key
319                        // NOTE: this call leaves the tsd LOCKED !!!!
320                        // @exception IPCException
321 kumpf         1.59     inline void *reference_tsd(const char* key)
322 mike          1.58     {
323                            _tsd.lock();
324                            thread_data *tsd = _tsd.find(thread_data::equal, key);
325                            if (tsd != NULL)
326 kumpf         1.59             return (void *) (tsd->_data);
327 mike          1.58         else
328 kumpf         1.59             return NULL;
329 mike          1.58     }
330 mike          1.2  
331 mike          1.58     // @exception IPCException
332                        inline void *try_reference_tsd(const char *key)
333                        {
334                            _tsd.try_lock();
335                            thread_data *tsd = _tsd.find(thread_data::equal, key);
336                            if (tsd != NULL)
337 kumpf         1.59             return (void *) (tsd->_data);
338 mike          1.58         else
339 kumpf         1.59             return NULL;
340 mike          1.58     }
341 mike          1.2  
342 kumpf         1.48 
343 mike          1.58     // release the lock held on the tsd
344                        // NOTE: assumes a corresponding and prior call to reference_tsd() !!!
345                        // @exception IPCException
346                        inline void dereference_tsd()
347                        {
348                            _tsd.unlock();
349                        }
350 kumpf         1.48 
351 mike          1.58     // delete the tsd associated with the key
352                        // @exception IPCException
353                        inline void delete_tsd(const char *key)
354 kumpf         1.48     {
355 mike          1.58         AutoPtr < thread_data > tsd(_tsd.remove(thread_data::equal, key));
356 kumpf         1.48     }
357                    
358 mike          1.58     // @exception IPCException
359                        inline void empty_tsd()
360 kumpf         1.48     {
361 mike          1.58         _tsd.clear();
362 kumpf         1.48     }
363                    
364 mike          1.58     // create or re-initialize tsd associated with the key
365                        // if the tsd already exists, delete the existing buffer
366                        // @exception IPCException
367 kumpf         1.59     void put_tsd(
368                            const char* key,
369                            void (*delete_func) (void *),
370                            Uint32 size,
371                            void* value)
372 kumpf         1.48     {
373 mike          1.58         PEGASUS_ASSERT(key != NULL);
374 kumpf         1.59         AutoPtr<thread_data> tsd;
375                            // This may throw an IPCException
376                            tsd.reset(_tsd.remove(thread_data::equal, key));
377 mike          1.58         tsd.reset();
378 kumpf         1.59         AutoPtr<thread_data> ntsd(new thread_data(key));
379 mike          1.58         ntsd->put_data(delete_func, size, value);
380 kumpf         1.59         // This may throw an IPCException
381                            _tsd.insert_front(ntsd.get());
382 mike          1.58         ntsd.release();
383 kumpf         1.48     }
384 kumpf         1.59 
385 mike          1.58     inline ThreadReturnType get_exit()
386 kumpf         1.48     {
387 mike          1.58         return _exit_code;
388 kumpf         1.48     }
389 mike          1.58     inline ThreadType self()
390 kumpf         1.48     {
391 mike          1.58         return Threads::self();
392 kumpf         1.48     }
393                    
394 mike          1.58     ThreadHandle getThreadHandle()
395 kumpf         1.48     {
396 mike          1.58         return _handle;
397 kumpf         1.48     }
398                    
399 mike          1.58     void detach();
400                    
401 kumpf         1.59     //
402 mike          1.58     // Gets the Thread object associated with the caller's thread.
403                        // Note: this may return NULL if no Thread object is associated
404                        // with the caller's thread.
405 kumpf         1.59     //
406                        static Thread *getCurrent();
407 mike          1.58 
408 kumpf         1.59     //
409 mike          1.58     // Sets the Thread object associated with the caller's thread.
410                        // Note: the Thread object must be placed on the heap.
411 kumpf         1.59     //
412                        static void setCurrent(Thread* thrd);
413 mike          1.58 
414 kumpf         1.59     //
415 mike          1.58     // Gets the AcceptLanguageList object associated with the caller's
416                        // Thread.
417                        // Note: this may return NULL if no Thread object, or no
418                        // AcceptLanguageList object, is associated with the caller's thread.
419 kumpf         1.59     //
420                        static AcceptLanguageList* getLanguages();
421 mike          1.58 
422 kumpf         1.59     //
423 mike          1.58     // Sets the AcceptLanguageList object associated with the caller's
424                        // Thread.
425                        // Note: a Thread object must have been previously associated with
426                        // the caller's thread.
427                        // Note: the AcceptLanguageList object must be placed on the heap.
428 kumpf         1.59     //
429                        static void setLanguages(AcceptLanguageList* langs);
430 mike          1.58 
431 kumpf         1.59     //
432 mike          1.58     // Removes the AcceptLanguageList object associated with the caller's
433                        // Thread.
434 kumpf         1.59     //
435                        static void clearLanguages();
436 kumpf         1.48 
437 kumpf         1.59 private:
438 mike          1.58     Thread();
439 mike          1.2  
440 kumpf         1.59     static Sint8 initializeKey();
441 mike          1.2  
442 mike          1.58     // @exception IPCException
443                        inline void create_tsd(const char *key)
444                        {
445 kumpf         1.59         AutoPtr<thread_data> tsd(new thread_data(key));
446 mike          1.58         _tsd.insert_front(tsd.get());
447                            tsd.release();
448                        }
449 kumpf         1.59 
450 mike          1.58     ThreadHandle _handle;
451                        Boolean _is_detached;
452                        Boolean _cancel_enabled;
453                        Boolean _cancelled;
454                    
455                        // always pass this * as the void * parameter to the thread
456                        // store the user parameter in _thread_parm
457                    
458 kumpf         1.59     ThreadReturnType(PEGASUS_THREAD_CDECL* _start) (void *);
459                        List<cleanup_handler, Mutex> _cleanup;
460                        List<thread_data, Mutex> _tsd;
461 mike          1.58 
462 kumpf         1.59     void* _thread_parm;
463 mike          1.58     ThreadReturnType _exit_code;
464                        static Boolean _signals_blocked;
465 kumpf         1.59     static TSDKeyType _platform_thread_key;
466                        static Boolean _key_initialized;
467                        static Boolean _key_error;
468 mike          1.58 };
469 mike          1.2  
470                    PEGASUS_NAMESPACE_END
471                    
472                    #endif // Pegasus_Thread_h

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2