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
|