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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2