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
|