1 karl 1.34 //%2003////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.34 // 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 // IBM Corp.; EMC Corporation, The Open Group.
|
7 mike 1.2 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 kumpf 1.18 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
12 mike 1.2 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
|
15 kumpf 1.18 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
16 mike 1.2 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
17 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
18 kumpf 1.18 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
19 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
21 mike 1.2 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 //==============================================================================
25 //
26 // Author: Mike Day (mdday@us.ibm.com)
27 //
28 // Modified By: Markus Mueller
|
29 kumpf 1.36 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
30 a.arora 1.37 // Amit K Arora, IBM (amita@in.ibm.com) for PEP#101
|
31 mike 1.2 //
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.5 #include <Pegasus/Common/IPC.h>
|
40 kumpf 1.23 #include <Pegasus/Common/InternalException.h>
|
41 mike 1.2 #include <Pegasus/Common/DQueue.h>
|
42 chuck 1.28 #include <Pegasus/Common/AcceptLanguages.h> // l10n
|
43 kumpf 1.22 #include <Pegasus/Common/Linkage.h>
|
44 a.arora 1.37 #include <Pegasus/Common/AutoPtr.h>
|
45 mike 1.2
46 PEGASUS_NAMESPACE_BEGIN
47
48 class PEGASUS_COMMON_LINKAGE cleanup_handler
49 {
50
51 public:
52 cleanup_handler( void (*routine)(void *), void *arg ) : _routine(routine), _arg(arg) {}
53 ~cleanup_handler() {; }
54 inline Boolean operator==(const void *key) const
55 {
56 if(key == (void *)_routine)
57 return true;
58 return false;
59 }
60 inline Boolean operator ==(const cleanup_handler & b) const
61 {
62 return(operator==((const void *)b._routine));
63 }
64 private:
65 void execute(void) { _routine(_arg); }
66 mike 1.2 cleanup_handler();
67 void (*_routine)(void *);
68
69 void *_arg;
70 PEGASUS_CLEANUP_HANDLE _cleanup_buffer;
71 friend class DQueue<class cleanup_handler>;
72 friend class Thread;
73 };
74
75 ///////////////////////////////////////////////////////////////////////////////
76
77
78 class PEGASUS_COMMON_LINKAGE thread_data
79 {
80
81 public:
82 static void default_delete(void *data);
83
|
84 kumpf 1.7 thread_data( const Sint8 *key ) : _delete_func(NULL) , _data(NULL), _size(0)
|
85 mike 1.2 {
86 PEGASUS_ASSERT(key != NULL);
87 size_t keysize = strlen(key);
88 _key = new Sint8 [keysize + 1];
89 memcpy(_key, key, keysize);
90 _key[keysize] = 0x00;
91
92 }
93
|
94 kumpf 1.7 thread_data(const Sint8 *key, size_t size) : _delete_func(default_delete), _size(size)
|
95 mike 1.2 {
96 PEGASUS_ASSERT(key != NULL);
97 size_t keysize = strlen(key);
98 _key = new Sint8 [keysize + 1];
99 memcpy(_key, key, keysize);
100 _key[keysize] = 0x00;
101 _data = ::operator new(_size) ;
102
103 }
104
|
105 kumpf 1.7 thread_data(const Sint8 *key, size_t size, void *data) : _delete_func(default_delete), _size(size)
|
106 mike 1.2 {
107 PEGASUS_ASSERT(key != NULL);
108 PEGASUS_ASSERT(data != NULL);
109 size_t keysize = strlen(key);
110
111 _key = new Sint8[keysize + 1];
112 memcpy(_key, key, keysize);
113 _key[keysize] = 0x00;
114 _data = ::operator new(_size);
115 memcpy(_data, data, size);
116 }
117
118 ~thread_data()
119 {
120 if( _data != NULL)
121 if(_delete_func != NULL)
|
122 sage 1.9 {
|
123 mike 1.2 _delete_func( _data );
|
124 sage 1.9 }
|
125 mike 1.2 if( _key != NULL )
126 delete [] _key;
127 }
128
129 void put_data(void (*del)(void *), size_t size, void *data ) throw(NullPointer)
130 {
131 if(_data != NULL)
132 if(_delete_func != NULL)
133 _delete_func(_data);
134
135 _delete_func = del;
136 _data = data;
137 _size = size;
138 return ;
139 }
140
141 size_t get_size(void) { return _size; }
142
143 void get_data(void **data, size_t *size)
144 {
145 if(data == NULL || size == NULL)
146 mike 1.2 throw NullPointer();
147
148 *data = _data;
149 *size = _size;
150 return;
151
152 }
153
|
154 kumpf 1.17 void copy_data(void **buf, size_t *size) throw(NullPointer)
|
155 mike 1.2 {
156 if((buf == NULL) || (size == NULL))
157 throw NullPointer() ;
158 *buf = ::operator new(_size);
159 *size = _size;
160 memcpy(*buf, _data, _size);
161 return;
162 }
163
164 inline Boolean operator==(const void *key) const
165 {
166 if ( ! strcmp(_key, (Sint8 *)key))
167 return(true);
168 return(false);
169 }
|
170 mday 1.8
|
171 mike 1.2 inline Boolean operator==(const thread_data& b) const
172 {
173 return(operator==((const void *)b._key));
174 }
175
176 private:
177 void (*_delete_func) (void *data) ;
178 thread_data();
179 void *_data;
180 size_t _size;
181 Sint8 *_key;
182
183 friend class DQueue<thread_data>;
184 friend class Thread;
185 };
186
187
188 ///////////////////////////////////////////////////////////////////////////
189
190 class PEGASUS_COMMON_LINKAGE ThreadPool;
191
192 mike 1.2 class PEGASUS_COMMON_LINKAGE Thread
193 {
194
195 public:
196 Thread( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *start )(void *),
197 void *parameter, Boolean detached );
198
199 ~Thread();
200
|
201 kumpf 1.36 /**
202 Start the thread.
203 @return true if the thread is started successfully, false if the
204 resources necessary to start the thread are not currently
205 available. ATTN: The result is undefined for any other
206 type of failure. (See Bugzilla 972)
207 */
208 Boolean run(void);
|
209 mike 1.2
210 // get the user parameter
211 inline void *get_parm(void) { return _thread_parm; }
212
213 // send the thread a signal -- may not be appropriate due to Windows
214 // void kill(int signum);
215
216 // cancellation must be deferred (not asynchronous)
217 // for user-level threads the thread itself can decide
218 // when it should die.
219 void cancel(void);
220
221 // cancel if there is a pending cancellation request
|
222 kumpf 1.25 void test_cancel(void);
|
223 mike 1.2
|
224 mday 1.3 Boolean is_cancelled(void);
225
|
226 mike 1.2 // for user-level threads - put the calling thread
227 // to sleep and jump to the thread scheduler.
228 // platforms with preemptive scheduling and native threads
229 // can define this to be a no-op.
230 // platforms without preemptive scheduling like NetWare
231 // or gnu portable threads will have an existing
232 // routine that can be mapped to this method
233
234 void thread_switch(void);
235
|
236 david.eger 1.27 #if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)
|
237 mike 1.2 // suspend this thread
238 void suspend(void) ;
239
240 // resume this thread
241 void resume(void) ;
242 #endif
243
244 static void sleep(Uint32 msec) ;
245
246 // block the calling thread until this thread terminates
247 void join( void );
248 void thread_init(void);
249
250 // thread routine needs to call this function when
251 // it is ready to exit
|
252 kumpf 1.25 void exit_self(PEGASUS_THREAD_RETURN return_code) ;
|
253 mike 1.2
254 // stack of functions to be called when thread terminates
255 // will be called last in first out (LIFO)
256 void cleanup_push( void (*routine) (void *), void *parm ) throw(IPCException);
257 void cleanup_pop(Boolean execute = true) throw(IPCException);
258
259 // create and initialize a tsd
|
260 kumpf 1.7 inline void create_tsd(const Sint8 *key, int size, void *buffer) throw(IPCException)
|
261 mike 1.2 {
|
262 a.arora 1.37 AutoPtr<thread_data> tsd(new thread_data(key, size, buffer));
|
263 a.arora 1.38 _tsd.insert_first(tsd.get());
|
264 a.arora 1.37 tsd.release();
|
265 mike 1.2 }
266
267 // get the buffer associated with the key
268 // NOTE: this call leaves the tsd LOCKED !!!!
|
269 kumpf 1.7 inline void *reference_tsd(const Sint8 *key) throw(IPCException)
|
270 mike 1.2 {
271 _tsd.lock();
|
272 kumpf 1.7 thread_data *tsd = _tsd.reference((const void *)key);
|
273 mike 1.2 if(tsd != NULL)
274 return( (void *)(tsd->_data) );
275 else
276 return(NULL);
277 }
278
|
279 kumpf 1.7 inline void *try_reference_tsd(const Sint8 *key) throw(IPCException)
|
280 mike 1.2 {
281 _tsd.try_lock();
|
282 kumpf 1.7 thread_data *tsd = _tsd.reference((const void *)key);
|
283 mike 1.2 if(tsd != NULL)
284 return((void *)(tsd->_data) );
285 else
286 return(NULL);
287 }
288
289
290 // release the lock held on the tsd
291 // NOTE: assumes a corresponding and prior call to reference_tsd() !!!
292 inline void dereference_tsd(void) throw(IPCException)
293 {
294 _tsd.unlock();
295 }
296
297 // delete the tsd associated with the key
|
298 kumpf 1.7 inline void delete_tsd(const Sint8 *key) throw(IPCException)
|
299 mike 1.2 {
|
300 a.arora 1.37 AutoPtr<thread_data> tsd(_tsd.remove((const void *)key));
|
301 mike 1.2 }
302
|
303 kumpf 1.14 // Note: Caller must delete the thread_data object returned (if not null)
|
304 kumpf 1.7 inline void *remove_tsd(const Sint8 *key) throw(IPCException)
|
305 mike 1.2 {
|
306 kumpf 1.7 return(_tsd.remove((const void *)key));
|
307 mike 1.2 }
308
309 inline void empty_tsd(void) throw(IPCException)
310 {
|
311 mday 1.33
312 try
313 {
314
315 _tsd.try_lock();
316 }
317 catch(IPCException&)
318 {
319 return;
320 }
321
|
322 a.arora 1.37 AutoPtr<thread_data> tsd(_tsd.next(0));
323 while(tsd.get())
|
324 mday 1.33 {
|
325 a.arora 1.37 _tsd.remove_no_lock(tsd.get());
326 tsd.reset(_tsd.next(0));
|
327 mday 1.33 }
328 _tsd.unlock();
|
329 mike 1.2 }
330
331 // create or re-initialize tsd associated with the key
|
332 kumpf 1.14 // if the tsd already exists, delete the existing buffer
333 void put_tsd(const Sint8 *key, void (*delete_func)(void *), Uint32 size, void *value)
|
334 mike 1.2 throw(IPCException)
335
336 {
337 PEGASUS_ASSERT(key != NULL);
|
338 a.arora 1.37 AutoPtr<thread_data> tsd ;
339 tsd.reset(_tsd.remove((const void *)key)); // may throw an IPC exception
340 tsd.reset();
341 AutoPtr<thread_data> ntsd(new thread_data(key));
|
342 mike 1.2 ntsd->put_data(delete_func, size, value);
|
343 a.arora 1.37 try { _tsd.insert_first(ntsd.get()); }
344 catch(IPCException& e) { e = e; throw; }
345 ntsd.release();
|
346 mike 1.2 }
347 inline PEGASUS_THREAD_RETURN get_exit(void) { return _exit_code; }
348 inline PEGASUS_THREAD_TYPE self(void) {return pegasus_thread_self(); }
349
350 PEGASUS_THREAD_HANDLE getThreadHandle() {return _handle;}
351
352 inline Boolean operator==(const void *key) const
353 {
354 if ( (void *)this == key)
355 return(true);
356 return(false);
357 }
358 inline Boolean operator==(const Thread & b) const
359 {
360 return(operator==((const void *)&b ));
361 }
362
363 void detach(void);
|
364 chuck 1.28
|
365 chuck 1.29 //
366 // Gets the Thread object associated with the caller's thread.
|
367 chuck 1.31 // Note: this may return NULL if no Thread object is associated
368 // with the caller's thread.
|
369 chuck 1.29 //
|
370 chuck 1.28 static Thread * getCurrent(); // l10n
|
371 chuck 1.29
372 //
|
373 chuck 1.31 // Sets the Thread object associated with the caller's thread.
374 // Note: the Thread object must be placed on the heap.
|
375 chuck 1.29 //
376 static void setCurrent(Thread * thrd); // l10n
377
378 //
|
379 chuck 1.31 // Gets the AcceptLanguages object associated with the caller's
|
380 chuck 1.29 // Thread.
|
381 chuck 1.31 // Note: this may return NULL if no Thread object, or no
382 // AcceptLanguages object, is associated with the caller's thread.
|
383 chuck 1.29 //
|
384 chuck 1.28 static AcceptLanguages * getLanguages(); //l10n
385
|
386 chuck 1.29 //
|
387 chuck 1.31 // Sets the AcceptLanguages object associated with the caller's
|
388 chuck 1.29 // Thread.
|
389 chuck 1.31 // Note: a Thread object must have been previously associated with
390 // the caller's thread.
391 // Note: the AcceptLanguages object must be placed on the heap.
|
392 chuck 1.29 //
|
393 chuck 1.28 static void setLanguages(AcceptLanguages *langs); //l10n
394
|
395 chuck 1.29 //
|
396 chuck 1.31 // Removes the AcceptLanguages object associated with the caller's
|
397 chuck 1.29 // Thread.
398 //
|
399 chuck 1.28 static void clearLanguages(); //l10n
|
400 mike 1.2
401 private:
402 Thread();
|
403 chuck 1.29
404 static Sint8 initializeKey(); // l10n
405
|
406 kumpf 1.7 inline void create_tsd(const Sint8 *key ) throw(IPCException)
|
407 mike 1.2 {
|
408 a.arora 1.37 AutoPtr<thread_data> tsd(new thread_data(key));
|
409 a.arora 1.38 _tsd.insert_first(tsd.get());
410 tsd.release();
|
411 mike 1.2 }
412 PEGASUS_THREAD_HANDLE _handle;
413 Boolean _is_detached;
414 Boolean _cancel_enabled;
415 Boolean _cancelled;
416
417 PEGASUS_SEM_HANDLE _suspend_count;
418
419 // always pass this * as the void * parameter to the thread
420 // store the user parameter in _thread_parm
421
422 PEGASUS_THREAD_RETURN ( PEGASUS_THREAD_CDECL *_start)(void *) ;
423 DQueue<class cleanup_handler> _cleanup;
424 DQueue<class thread_data> _tsd;
425
426 void *_thread_parm;
427 PEGASUS_THREAD_RETURN _exit_code;
428 static Boolean _signals_blocked;
|
429 chuck 1.28 static PEGASUS_THREAD_KEY_TYPE _platform_thread_key; //l10n
|
430 chuck 1.30 static Boolean _key_initialized; // l10n
431 static Boolean _key_error; // l10n
|
432 mike 1.2 friend class ThreadPool;
433 } ;
434
435
436 class PEGASUS_COMMON_LINKAGE ThreadPool
437 {
438 public:
439
440 ThreadPool(Sint16 initial_size,
|
441 kumpf 1.7 const Sint8 *key,
|
442 mike 1.2 Sint16 min,
443 Sint16 max,
444 struct timeval & alloc_wait,
445 struct timeval & dealloc_wait,
446 struct timeval & deadlock_detect);
447
448 ~ThreadPool(void);
449
|
450 kumpf 1.36 /**
451 Allocate and start a thread to do a unit of work.
452 @param parm A generic parameter to pass to the thread
453 @param work A pointer to the function that is to be executed by
454 the thread
455 @param blocking A pointer to an optional semaphore which, if
456 specified, is signaled after the thread finishes
457 executing the work function
458 @return true if the thread is started successfully, false if the
459 resources necessary to start the thread are not currently
460 available. ATTN: The result is undefined for any other
461 type of thread creation failure.
462 */
463 Boolean allocate_and_awaken(void *parm,
464 PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *work)(void *),
465 Semaphore *blocking = 0)
|
466 mday 1.8 throw(IPCException);
467
468
469 Uint32 kill_dead_threads( void )
|
470 mike 1.2 throw(IPCException);
471
472 void get_key(Sint8 *buf, int bufsize);
473
474 inline Boolean operator==(const void *key) const
475 {
476 if ( ! strncmp( reinterpret_cast<Sint8 *>(const_cast<void *>(key)), _key, 16 ))
477 return(true);
478 return(false);
479 }
480 inline Boolean operator==(const ThreadPool & b) const
481 {
482 return(operator==((const void *) b._key ));
483 }
484
485 inline void set_min_threads(Sint16 min)
486 {
487 _min_threads = min;
488 }
489
490 inline Sint16 get_min_threads(void) const
491 mike 1.2 {
492 return _min_threads;
493 }
494
495 inline void set_max_threads(Sint16 max)
496 {
497 _max_threads = max;
498 }
499
500 inline Sint16 get_max_threads(void) const
501 {
502 return _max_threads;
503 }
504
505 inline void set_allocate_wait(const struct timeval & alloc_wait)
506 {
507 _allocate_wait.tv_sec = alloc_wait.tv_sec;
508 _allocate_wait.tv_usec = alloc_wait.tv_usec;
509 }
510
511 inline struct timeval *get_allocate_wait(struct timeval *buffer) const
512 mike 1.2 {
513 if(buffer == 0)
514 throw NullPointer();
515 buffer->tv_sec = _allocate_wait.tv_sec;
516 buffer->tv_usec = _allocate_wait.tv_usec;
517 return buffer;
518 }
519
520 inline void set_deallocate_wait(const struct timeval & dealloc_wait)
521 {
522 _deallocate_wait.tv_sec = dealloc_wait.tv_sec;
523 _deallocate_wait.tv_usec = dealloc_wait.tv_usec;
524 }
525
526 inline struct timeval *get_deallocate_wait(struct timeval *buffer) const
527 {
528 if(buffer == 0)
529 throw NullPointer();
530 buffer->tv_sec = _deallocate_wait.tv_sec;
531 buffer->tv_usec = _deallocate_wait.tv_usec;
532 return buffer;
533 mike 1.2 }
534
535 inline void set_deadlock_detect(const struct timeval & deadlock)
536 {
537 _deadlock_detect.tv_sec = deadlock.tv_sec;
538 _deadlock_detect.tv_usec = deadlock.tv_usec;
539 }
540
541 inline struct timeval * get_deadlock_detect(struct timeval *buffer) const
542 {
543 if(buffer == 0)
544 throw NullPointer();
545 buffer->tv_sec = _deadlock_detect.tv_sec;
546 buffer->tv_usec = _deadlock_detect.tv_usec;
547 return buffer;
548 }
549
550 inline Uint32 running_count(void)
551 {
552 return _running.count();
553 }
|
554 mday 1.19
555 inline Uint32 pool_count(void)
556 {
557 return _pool.count();
558 }
559 inline Uint32 dead_count(void)
560 {
561 return _dead.count();
562 }
563
|
564 mike 1.2
565 static Boolean check_time(struct timeval *start, struct timeval *interval);
566
|
567 mday 1.21 Boolean operator ==(const ThreadPool & p)
568 {
569 return operator==((const void *)&p);
570 }
571
572 Boolean operator ==(const void *p)
573 {
574 if((void *)this == p)
575 return true;
576 return false;
577 }
578
579 static void kill_idle_threads(void);
580
|
581 mike 1.2 private:
582 ThreadPool(void);
583 Sint16 _max_threads;
584 Sint16 _min_threads;
585 AtomicInt _current_threads;
586 struct timeval _allocate_wait;
587 struct timeval _deallocate_wait;
588 struct timeval _deadlock_detect;
589 static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL _loop(void *);
590 Sint8 _key[17];
591 DQueue<Thread> _pool;
592 DQueue<Thread> _running;
593 DQueue<Thread> _dead;
594 AtomicInt _dying;
|
595 mday 1.32
|
596 mike 1.2 static void _sleep_sem_del(void *p);
597
598 void _check_deadlock(struct timeval *start) throw(Deadlock);
599 Boolean _check_deadlock_no_throw(struct timeval *start);
600 Boolean _check_dealloc(struct timeval *start);
601 Thread *_init_thread(void) throw(IPCException);
602 void _link_pool(Thread *th) throw(IPCException);
603 static PEGASUS_THREAD_RETURN _undertaker(void *);
|
604 mday 1.21 static DQueue<ThreadPool> _pools;
|
605 mike 1.2 };
606
607
608
609
610 #if defined(PEGASUS_OS_TYPE_WINDOWS)
611 # include "ThreadWindows_inline.h"
|
612 sage 1.6 #elif defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM)
613 # include "ThreadzOS_inline.h"
|
614 mike 1.2 #elif defined(PEGASUS_OS_TYPE_UNIX)
615 # include "ThreadUnix_inline.h"
616 #endif
617
618 PEGASUS_NAMESPACE_END
619
620 #endif // Pegasus_Thread_h
|