version 1.53, 2005/06/24 19:34:23
|
version 1.57.2.1, 2006/07/27 23:11:52
|
|
|
//%2005//////////////////////////////////////////////////////////////////////// |
//%2006//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development | // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. | // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
|
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. | // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; | // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
// EMC Corporation; VERITAS Software Corporation; The Open Group. | // EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; Symantec Corporation; The Open Group. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy | // Permission is hereby granted, free of charge, to any person obtaining a copy |
// of this software and associated documentation files (the "Software"), to | // of this software and associated documentation files (the "Software"), to |
|
|
| |
#include <cstring> | #include <cstring> |
#include <Pegasus/Common/Config.h> | #include <Pegasus/Common/Config.h> |
#include <Pegasus/Common/IPC.h> |
#include <Pegasus/Common/AtomicInt.h> |
#include <Pegasus/Common/InternalException.h> | #include <Pegasus/Common/InternalException.h> |
#include <Pegasus/Common/DQueue.h> |
#include <Pegasus/Common/AcceptLanguageList.h> |
#include <Pegasus/Common/AcceptLanguages.h> // l10n |
|
#include <Pegasus/Common/Linkage.h> | #include <Pegasus/Common/Linkage.h> |
#include <Pegasus/Common/AutoPtr.h> | #include <Pegasus/Common/AutoPtr.h> |
|
#include <Pegasus/Common/List.h> |
|
#include <Pegasus/Common/Mutex.h> |
|
#include <Pegasus/Common/Semaphore.h> |
|
#include <Pegasus/Common/TSDKey.h> |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
class PEGASUS_COMMON_LINKAGE cleanup_handler |
class PEGASUS_COMMON_LINKAGE cleanup_handler : public Linkable |
{ | { |
| |
public: | public: |
cleanup_handler( void (*routine)(void *), void *arg ) : _routine(routine), _arg(arg) {} | cleanup_handler( void (*routine)(void *), void *arg ) : _routine(routine), _arg(arg) {} |
~cleanup_handler() {; } | ~cleanup_handler() {; } |
inline Boolean operator==(const void *key) const |
|
{ |
|
if(key == (void *)_routine) |
|
return true; |
|
return false; |
|
} |
|
inline Boolean operator ==(const cleanup_handler & b) const |
|
{ |
|
return(operator==((const void *)b._routine)); |
|
} |
|
private: | private: |
void execute() { _routine(_arg); } | void execute() { _routine(_arg); } |
cleanup_handler(); | cleanup_handler(); |
void (*_routine)(void *); | void (*_routine)(void *); |
| |
void *_arg; | void *_arg; |
PEGASUS_CLEANUP_HANDLE _cleanup_buffer; |
ThreadCleanupType _cleanup_buffer; |
friend class DQueue<class cleanup_handler>; |
|
friend class Thread; | friend class Thread; |
}; | }; |
| |
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// |
| |
| |
class PEGASUS_COMMON_LINKAGE thread_data |
class PEGASUS_COMMON_LINKAGE thread_data : public Linkable |
{ | { |
| |
public: | public: |
|
|
return(operator==(b._key.get())); | return(operator==(b._key.get())); |
} | } |
| |
|
static bool equal(const thread_data* node, const void* key) |
|
{ |
|
return ((thread_data*)node)->operator==(key); |
|
} |
|
|
private: | private: |
void (*_delete_func) (void *data); | void (*_delete_func) (void *data); |
thread_data(); | thread_data(); |
|
|
size_t _size; | size_t _size; |
AutoArrayPtr<char> _key; | AutoArrayPtr<char> _key; |
| |
friend class DQueue<thread_data>; |
|
friend class Thread; | friend class Thread; |
}; | }; |
| |
|
|
| |
/////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////// |
| |
class PEGASUS_COMMON_LINKAGE Thread |
class PEGASUS_COMMON_LINKAGE Thread : public Linkable |
{ | { |
public: | public: |
| |
Thread( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *start )(void *), |
Thread( ThreadReturnType (PEGASUS_THREAD_CDECL *start )(void *), |
void *parameter, Boolean detached ); | void *parameter, Boolean detached ); |
| |
~Thread(); | ~Thread(); |
|
|
| |
// thread routine needs to call this function when | // thread routine needs to call this function when |
// it is ready to exit | // it is ready to exit |
void exit_self(PEGASUS_THREAD_RETURN return_code); |
void exit_self(ThreadReturnType return_code); |
| |
// stack of functions to be called when thread terminates | // stack of functions to be called when thread terminates |
// will be called last in first out (LIFO) | // will be called last in first out (LIFO) |
|
|
inline void create_tsd(const char *key, int size, void *buffer) | inline void create_tsd(const char *key, int size, void *buffer) |
{ | { |
AutoPtr<thread_data> tsd(new thread_data(key, size, buffer)); | AutoPtr<thread_data> tsd(new thread_data(key, size, buffer)); |
_tsd.insert_first(tsd.get()); |
_tsd.insert_front(tsd.get()); |
tsd.release(); | tsd.release(); |
} | } |
| |
|
|
inline void *reference_tsd(const char *key) | inline void *reference_tsd(const char *key) |
{ | { |
_tsd.lock(); | _tsd.lock(); |
thread_data *tsd = _tsd.reference(key); |
thread_data *tsd = _tsd.find(thread_data::equal, key); |
if(tsd != NULL) | if(tsd != NULL) |
return( (void *)(tsd->_data) ); | return( (void *)(tsd->_data) ); |
else | else |
|
|
inline void *try_reference_tsd(const char *key) | inline void *try_reference_tsd(const char *key) |
{ | { |
_tsd.try_lock(); | _tsd.try_lock(); |
thread_data *tsd = _tsd.reference(key); |
thread_data *tsd = _tsd.find(thread_data::equal, key); |
if(tsd != NULL) | if(tsd != NULL) |
return((void *)(tsd->_data) ); | return((void *)(tsd->_data) ); |
else | else |
|
|
// @exception IPCException | // @exception IPCException |
inline void delete_tsd(const char *key) | inline void delete_tsd(const char *key) |
{ | { |
AutoPtr<thread_data> tsd(_tsd.remove(key)); |
AutoPtr<thread_data> tsd(_tsd.remove(thread_data::equal, key)); |
} |
|
|
|
// Note: Caller must delete the thread_data object returned (if not null) |
|
// @exception IPCException |
|
inline void *remove_tsd(const char *key) |
|
{ |
|
return(_tsd.remove((const void *)key)); |
|
} | } |
| |
// @exception IPCException | // @exception IPCException |
inline void empty_tsd() | inline void empty_tsd() |
{ | { |
try |
_tsd.clear(); |
{ |
|
_tsd.try_lock(); |
|
} |
|
catch(IPCException&) |
|
{ |
|
return; |
|
} |
|
|
|
AutoPtr<thread_data> tsd(_tsd.next(0)); |
|
while(tsd.get()) |
|
{ |
|
_tsd.remove_no_lock(tsd.get()); |
|
tsd.reset(_tsd.next(0)); |
|
} |
|
_tsd.unlock(); |
|
} | } |
| |
// create or re-initialize tsd associated with the key | // create or re-initialize tsd associated with the key |
|
|
{ | { |
PEGASUS_ASSERT(key != NULL); | PEGASUS_ASSERT(key != NULL); |
AutoPtr<thread_data> tsd; | AutoPtr<thread_data> tsd; |
tsd.reset(_tsd.remove((const void *)key)); // may throw an IPC exception |
tsd.reset(_tsd.remove(thread_data::equal, key)); // may throw an IPC exception |
tsd.reset(); | tsd.reset(); |
AutoPtr<thread_data> ntsd(new thread_data(key)); | AutoPtr<thread_data> ntsd(new thread_data(key)); |
ntsd->put_data(delete_func, size, value); | ntsd->put_data(delete_func, size, value); |
try { _tsd.insert_first(ntsd.get()); } |
try { _tsd.insert_front(ntsd.get()); } |
catch(IPCException& e) { e = e; throw; } | catch(IPCException& e) { e = e; throw; } |
ntsd.release(); | ntsd.release(); |
} | } |
inline PEGASUS_THREAD_RETURN get_exit() { return _exit_code; } |
inline ThreadReturnType get_exit() { return _exit_code; } |
inline PEGASUS_THREAD_TYPE self() {return pegasus_thread_self(); } |
inline ThreadType self() {return Threads::self(); } |
|
|
PEGASUS_THREAD_HANDLE getThreadHandle() {return _handle;} |
|
| |
inline Boolean operator==(const void *key) const |
ThreadHandle getThreadHandle() {return _handle;} |
{ |
|
if ( (void *)this == key) |
|
return(true); |
|
return(false); |
|
} |
|
inline Boolean operator==(const Thread & b) const |
|
{ |
|
return(operator==((const void *)&b )); |
|
} |
|
| |
void detach(); | void detach(); |
| |
|
|
static void setCurrent(Thread * thrd); // l10n | static void setCurrent(Thread * thrd); // l10n |
| |
// | // |
// Gets the AcceptLanguages object associated with the caller's |
// Gets the AcceptLanguageList object associated with the caller's |
// Thread. | // Thread. |
// Note: this may return NULL if no Thread object, or no | // Note: this may return NULL if no Thread object, or no |
// AcceptLanguages object, is associated with the caller's thread. |
// AcceptLanguageList object, is associated with the caller's thread. |
// | // |
static AcceptLanguages * getLanguages(); //l10n |
static AcceptLanguageList * getLanguages(); //l10n |
| |
// | // |
// Sets the AcceptLanguages object associated with the caller's |
// Sets the AcceptLanguageList object associated with the caller's |
// Thread. | // Thread. |
// Note: a Thread object must have been previously associated with | // Note: a Thread object must have been previously associated with |
// the caller's thread. | // the caller's thread. |
// Note: the AcceptLanguages object must be placed on the heap. |
// Note: the AcceptLanguageList object must be placed on the heap. |
// | // |
static void setLanguages(AcceptLanguages *langs); //l10n |
static void setLanguages(AcceptLanguageList *langs); //l10n |
| |
// | // |
// Removes the AcceptLanguages object associated with the caller's |
// Removes the AcceptLanguageList object associated with the caller's |
// Thread. | // Thread. |
// | // |
static void clearLanguages(); //l10n | static void clearLanguages(); //l10n |
|
|
inline void create_tsd(const char *key ) | inline void create_tsd(const char *key ) |
{ | { |
AutoPtr<thread_data> tsd(new thread_data(key)); | AutoPtr<thread_data> tsd(new thread_data(key)); |
_tsd.insert_first(tsd.get()); |
_tsd.insert_front(tsd.get()); |
tsd.release(); | tsd.release(); |
} | } |
PEGASUS_THREAD_HANDLE _handle; |
ThreadHandle _handle; |
Boolean _is_detached; | Boolean _is_detached; |
Boolean _cancel_enabled; | Boolean _cancel_enabled; |
Boolean _cancelled; | Boolean _cancelled; |
| |
PEGASUS_SEM_HANDLE _suspend_count; |
|
|
|
// always pass this * as the void * parameter to the thread | // always pass this * as the void * parameter to the thread |
// store the user parameter in _thread_parm | // store the user parameter in _thread_parm |
| |
PEGASUS_THREAD_RETURN ( PEGASUS_THREAD_CDECL *_start)(void *); |
ThreadReturnType ( PEGASUS_THREAD_CDECL *_start)(void *); |
DQueue<class cleanup_handler> _cleanup; |
List<cleanup_handler, Mutex> _cleanup; |
DQueue<class thread_data> _tsd; |
List<thread_data, Mutex> _tsd; |
| |
void *_thread_parm; | void *_thread_parm; |
PEGASUS_THREAD_RETURN _exit_code; |
ThreadReturnType _exit_code; |
static Boolean _signals_blocked; | static Boolean _signals_blocked; |
static PEGASUS_THREAD_KEY_TYPE _platform_thread_key; //l10n |
static TSDKeyType _platform_thread_key; //l10n |
static Boolean _key_initialized; // l10n | static Boolean _key_initialized; // l10n |
static Boolean _key_error; // l10n | static Boolean _key_error; // l10n |
}; | }; |
|
|
*/ | */ |
ThreadStatus allocate_and_awaken( | ThreadStatus allocate_and_awaken( |
void* parm, | void* parm, |
PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL* work)(void *), |
ThreadReturnType (PEGASUS_THREAD_CDECL* work)(void *), |
Semaphore* blocking = 0); | Semaphore* blocking = 0); |
| |
/** | /** |
|
|
| |
void get_key(Sint8* buf, int bufsize); | void get_key(Sint8* buf, int bufsize); |
| |
inline Boolean operator==(const char* key) const |
|
{ |
|
return (!strncmp(key, _key, 16)); |
|
} |
|
|
|
Boolean operator==(const void* p) const |
|
{ |
|
return ((void *)this == p); |
|
} |
|
|
|
Boolean operator==(const ThreadPool & p) const |
|
{ |
|
return operator==((const void *)&p); |
|
} |
|
|
|
inline void setMinThreads(Sint16 min) | inline void setMinThreads(Sint16 min) |
{ | { |
_minThreads = min; | _minThreads = min; |
|
|
| |
inline Uint32 runningCount() | inline Uint32 runningCount() |
{ | { |
return _runningThreads.count(); |
return _runningThreads.size(); |
} | } |
| |
inline Uint32 idleCount() | inline Uint32 idleCount() |
{ | { |
return _idleThreads.count(); |
return _idleThreads.size(); |
} | } |
| |
private: | private: |
|
|
ThreadPool(const ThreadPool&); // Unimplemented | ThreadPool(const ThreadPool&); // Unimplemented |
ThreadPool& operator=(const ThreadPool&); // Unimplemented | ThreadPool& operator=(const ThreadPool&); // Unimplemented |
| |
static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL _loop(void *); |
static ThreadReturnType PEGASUS_THREAD_CDECL _loop(void *); |
| |
static Boolean _timeIntervalExpired( | static Boolean _timeIntervalExpired( |
struct timeval* start, | struct timeval* start, |
|
|
AtomicInt _currentThreads; | AtomicInt _currentThreads; |
struct timeval _deallocateWait; | struct timeval _deallocateWait; |
char _key[17]; | char _key[17]; |
DQueue<Thread> _idleThreads; |
List<Thread, Mutex> _idleThreads; |
DQueue<Thread> _runningThreads; |
List<Thread, Mutex> _runningThreads; |
AtomicInt _dying; | AtomicInt _dying; |
}; | }; |
| |