(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                        // for user-level threads - put the calling thread
269                        // to sleep and jump to the thread scheduler.
270                        // platforms with preemptive scheduling and native threads
271                        // can define this to be a no-op.
272                        // platforms without preemptive scheduling like NetWare
273                        // or gnu portable threads will have an existing
274                        // routine that can be mapped to this method
275 mike          1.2  
276 mike          1.58     void thread_switch();
277 mike          1.2  
278 mike          1.58     static void sleep(Uint32 msec);
279 mike          1.2  
280 mike          1.58     // block the calling thread until this thread terminates
281                        void join();
282                    
283                        // thread routine needs to call this function when
284                        // it is ready to exit
285                        void exit_self(ThreadReturnType return_code);
286                    
287                        // stack of functions to be called when thread terminates
288                        // will be called last in first out (LIFO)
289                        // @exception IPCException
290 kumpf         1.59     void cleanup_push(void (*routine) (void *), void* parm);
291 mike          1.58 
292                        // @exception IPCException
293                        void cleanup_pop(Boolean execute = true);
294                    
295                        // create and initialize a tsd
296                        // @exception IPCException
297 kumpf         1.59     inline void create_tsd(const char* key, int size, void* buffer)
298 mike          1.58     {
299 kumpf         1.59         AutoPtr<thread_data> tsd(new thread_data(key, size, buffer));
300 mike          1.56         _tsd.insert_front(tsd.get());
301 a.arora       1.37         tsd.release();
302 mike          1.58     }
303 mike          1.2  
304 mike          1.58     // get the buffer associated with the key
305                        // NOTE: this call leaves the tsd LOCKED !!!!
306                        // @exception IPCException
307 kumpf         1.59     inline void *reference_tsd(const char* key)
308 mike          1.58     {
309                            _tsd.lock();
310                            thread_data *tsd = _tsd.find(thread_data::equal, key);
311                            if (tsd != NULL)
312 kumpf         1.59             return (void *) (tsd->_data);
313 mike          1.58         else
314 kumpf         1.59             return NULL;
315 mike          1.58     }
316 mike          1.2  
317 mike          1.58     // @exception IPCException
318                        inline void *try_reference_tsd(const char *key)
319                        {
320                            _tsd.try_lock();
321                            thread_data *tsd = _tsd.find(thread_data::equal, key);
322                            if (tsd != NULL)
323 kumpf         1.59             return (void *) (tsd->_data);
324 mike          1.58         else
325 kumpf         1.59             return NULL;
326 mike          1.58     }
327 mike          1.2  
328 kumpf         1.48 
329 mike          1.58     // release the lock held on the tsd
330                        // NOTE: assumes a corresponding and prior call to reference_tsd() !!!
331                        // @exception IPCException
332                        inline void dereference_tsd()
333                        {
334                            _tsd.unlock();
335                        }
336 kumpf         1.48 
337 mike          1.58     // delete the tsd associated with the key
338                        // @exception IPCException
339                        inline void delete_tsd(const char *key)
340 kumpf         1.48     {
341 mike          1.58         AutoPtr < thread_data > tsd(_tsd.remove(thread_data::equal, key));
342 kumpf         1.48     }
343                    
344 mike          1.58     // @exception IPCException
345                        inline void empty_tsd()
346 kumpf         1.48     {
347 mike          1.58         _tsd.clear();
348 kumpf         1.48     }
349                    
350 mike          1.58     // create or re-initialize tsd associated with the key
351                        // if the tsd already exists, delete the existing buffer
352                        // @exception IPCException
353 kumpf         1.59     void put_tsd(
354                            const char* key,
355                            void (*delete_func) (void *),
356                            Uint32 size,
357                            void* value)
358 kumpf         1.48     {
359 mike          1.58         PEGASUS_ASSERT(key != NULL);
360 kumpf         1.59         AutoPtr<thread_data> tsd;
361                            // This may throw an IPCException
362                            tsd.reset(_tsd.remove(thread_data::equal, key));
363 mike          1.58         tsd.reset();
364 kumpf         1.59         AutoPtr<thread_data> ntsd(new thread_data(key));
365 mike          1.58         ntsd->put_data(delete_func, size, value);
366 kumpf         1.59         // This may throw an IPCException
367                            _tsd.insert_front(ntsd.get());
368 mike          1.58         ntsd.release();
369 kumpf         1.48     }
370 kumpf         1.59 
371 mike          1.58     inline ThreadReturnType get_exit()
372 kumpf         1.48     {
373 mike          1.58         return _exit_code;
374 kumpf         1.48     }
375 mike          1.58     inline ThreadType self()
376 kumpf         1.48     {
377 mike          1.58         return Threads::self();
378 kumpf         1.48     }
379                    
380 mike          1.58     ThreadHandle getThreadHandle()
381 kumpf         1.48     {
382 mike          1.58         return _handle;
383 kumpf         1.48     }
384                    
385 mike          1.58     void detach();
386                    
387 kumpf         1.59     //
388 mike          1.58     // Gets the Thread object associated with the caller's thread.
389                        // Note: this may return NULL if no Thread object is associated
390                        // with the caller's thread.
391 kumpf         1.59     //
392                        static Thread *getCurrent();
393 mike          1.58 
394 kumpf         1.59     //
395 mike          1.58     // Sets the Thread object associated with the caller's thread.
396                        // Note: the Thread object must be placed on the heap.
397 kumpf         1.59     //
398                        static void setCurrent(Thread* thrd);
399 mike          1.58 
400 kumpf         1.59     //
401 mike          1.58     // Gets the AcceptLanguageList object associated with the caller's
402                        // Thread.
403                        // Note: this may return NULL if no Thread object, or no
404                        // AcceptLanguageList object, is associated with the caller's thread.
405 kumpf         1.59     //
406                        static AcceptLanguageList* getLanguages();
407 mike          1.58 
408 kumpf         1.59     //
409 mike          1.58     // Sets the AcceptLanguageList object associated with the caller's
410                        // Thread.
411                        // Note: a Thread object must have been previously associated with
412                        // the caller's thread.
413 kumpf         1.59     //
414 kumpf         1.60     static void setLanguages(const AcceptLanguageList& langs);
415 mike          1.58 
416 kumpf         1.59     //
417 mike          1.58     // Removes the AcceptLanguageList object associated with the caller's
418                        // Thread.
419 kumpf         1.59     //
420                        static void clearLanguages();
421 kumpf         1.48 
422 kumpf         1.59 private:
423 mike          1.58     Thread();
424 mike          1.2  
425 kumpf         1.59     static Sint8 initializeKey();
426 mike          1.2  
427 mike          1.58     // @exception IPCException
428                        inline void create_tsd(const char *key)
429                        {
430 kumpf         1.59         AutoPtr<thread_data> tsd(new thread_data(key));
431 mike          1.58         _tsd.insert_front(tsd.get());
432                            tsd.release();
433                        }
434 kumpf         1.59 
435 mike          1.58     ThreadHandle _handle;
436                        Boolean _is_detached;
437                        Boolean _cancelled;
438                    
439                        // always pass this * as the void * parameter to the thread
440                        // store the user parameter in _thread_parm
441                    
442 kumpf         1.59     ThreadReturnType(PEGASUS_THREAD_CDECL* _start) (void *);
443                        List<cleanup_handler, Mutex> _cleanup;
444                        List<thread_data, Mutex> _tsd;
445 mike          1.58 
446 kumpf         1.59     void* _thread_parm;
447 mike          1.58     ThreadReturnType _exit_code;
448                        static Boolean _signals_blocked;
449 kumpf         1.59     static TSDKeyType _platform_thread_key;
450                        static Boolean _key_initialized;
451                        static Boolean _key_error;
452 mike          1.58 };
453 mike          1.2  
454                    PEGASUS_NAMESPACE_END
455                    
456                    #endif // Pegasus_Thread_h

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2