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
|