version 1.24, 2002/09/17 18:01:03
|
version 1.42.2.2, 2005/08/16 17:30:51
|
|
|
//%/-*-c++-*-//////////////////////////////////////////////////////////////////////////// |
//%2004//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM, |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// The Open Group, Tivoli Systems |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation, The Open Group. |
|
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation; VERITAS Software 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 |
|
|
// Author: Mike Day (mdday@us.ibm.com) | // Author: Mike Day (mdday@us.ibm.com) |
// | // |
// Modified By: Markus Mueller | // Modified By: Markus Mueller |
|
// Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) |
|
// Amit K Arora, IBM (amita@in.ibm.com) for PEP#101 |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
#ifndef Pegasus_Thread_h | #ifndef Pegasus_Thread_h |
#define Pegasus_Thread_h | #define Pegasus_Thread_h |
|
|
|
#include <cstring> |
#include <Pegasus/Common/Config.h> | #include <Pegasus/Common/Config.h> |
#include <Pegasus/Common/IPC.h> | #include <Pegasus/Common/IPC.h> |
#include <Pegasus/Common/InternalException.h> | #include <Pegasus/Common/InternalException.h> |
#include <Pegasus/Common/DQueue.h> | #include <Pegasus/Common/DQueue.h> |
|
#include <Pegasus/Common/AcceptLanguages.h> // l10n |
#include <Pegasus/Common/Linkage.h> | #include <Pegasus/Common/Linkage.h> |
|
#include <Pegasus/Common/AutoPtr.h> |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
|
|
delete [] _key; | delete [] _key; |
} | } |
| |
|
/** |
|
* This function is used to put data in thread space. |
|
* |
|
* Be aware that there is NOTHING in place to stop |
|
* other users of the thread to remove this data. |
|
* Or change the data. |
|
* |
|
* You, the developer has to make sure that there are |
|
* no situations in which this can arise (ie, have a |
|
* lock for the function which manipulates the TSD. |
|
*/ |
void put_data(void (*del)(void *), size_t size, void *data ) throw(NullPointer) | void put_data(void (*del)(void *), size_t size, void *data ) throw(NullPointer) |
{ | { |
if(_data != NULL) | if(_data != NULL) |
|
|
| |
size_t get_size(void) { return _size; } | size_t get_size(void) { return _size; } |
| |
|
/** |
|
* This function is used to retrieve data from the |
|
* TSD, the thread specific data. |
|
* |
|
* Be aware that there is NOTHING in place to stop |
|
* other users of the thread to change the data you |
|
* get from this function. |
|
* |
|
* You, the developer has to make sure that there are |
|
* no situations in which this can arise (ie, have a |
|
* lock for the function which manipulates the TSD. |
|
*/ |
void get_data(void **data, size_t *size) | void get_data(void **data, size_t *size) |
{ | { |
if(data == NULL || size == NULL) | if(data == NULL || size == NULL) |
|
|
friend class Thread; | friend class Thread; |
}; | }; |
| |
|
enum ThreadStatus { |
|
PEGASUS_THREAD_OK = 1, /* No problems */ |
|
PEGASUS_THREAD_INSUFFICIENT_RESOURCES, /* Can't allocate a thread. Not enough |
|
memory. Try again later */ |
|
PEGASUS_THREAD_SETUP_FAILURE, /* Could not allocate into the thread specific |
|
data storage. */ |
|
PEGASUS_THREAD_UNAVAILABLE /* Service is being destroyed and no new threads can |
|
be provided. */ |
|
}; |
| |
/////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////// |
| |
|
|
| |
~Thread(); | ~Thread(); |
| |
void run(void); |
/** |
|
Start the thread. |
|
@return PEGASUS_THREAD_OK if the thread is started successfully, |
|
PEGASUS_THREAD_INSUFFICIENT_RESOURCES if the resources necessary |
|
to start the thread are not currently available. |
|
PEGASUS_THREAD_SETUP_FAILURE if the thread could not |
|
be create properly - check the 'errno' value for specific operating |
|
system return code. |
|
*/ |
|
ThreadStatus run(); |
| |
// get the user parameter | // get the user parameter |
inline void *get_parm(void) { return _thread_parm; } | inline void *get_parm(void) { return _thread_parm; } |
|
|
void cancel(void); | void cancel(void); |
| |
// cancel if there is a pending cancellation request | // cancel if there is a pending cancellation request |
static void test_cancel(void); |
void test_cancel(void); |
| |
Boolean is_cancelled(void); | Boolean is_cancelled(void); |
| |
|
|
| |
void thread_switch(void); | void thread_switch(void); |
| |
#if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
#if defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) |
// suspend this thread | // suspend this thread |
void suspend(void) ; | void suspend(void) ; |
| |
|
|
| |
// 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 |
static void exit_self(PEGASUS_THREAD_RETURN return_code) ; |
void exit_self(PEGASUS_THREAD_RETURN 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) |
|
|
// create and initialize a tsd | // create and initialize a tsd |
inline void create_tsd(const Sint8 *key, int size, void *buffer) throw(IPCException) | inline void create_tsd(const Sint8 *key, int size, void *buffer) throw(IPCException) |
{ | { |
thread_data *tsd = new thread_data(key, size, buffer); |
AutoPtr<thread_data> tsd(new thread_data(key, size, buffer)); |
try { _tsd.insert_first(tsd); } |
_tsd.insert_first(tsd.get()); |
catch(IPCException& e) { e = e; delete tsd; throw; } |
tsd.release(); |
} | } |
| |
// get the buffer associated with the key | // get the buffer associated with the key |
|
|
// delete the tsd associated with the key | // delete the tsd associated with the key |
inline void delete_tsd(const Sint8 *key) throw(IPCException) | inline void delete_tsd(const Sint8 *key) throw(IPCException) |
{ | { |
thread_data *tsd = _tsd.remove((const void *)key); |
AutoPtr<thread_data> tsd(_tsd.remove((const void *)key)); |
if(tsd != NULL) |
|
delete tsd; |
|
} | } |
| |
// Note: Caller must delete the thread_data object returned (if not null) | // Note: Caller must delete the thread_data object returned (if not null) |
|
|
| |
inline void empty_tsd(void) throw(IPCException) | inline void empty_tsd(void) throw(IPCException) |
{ | { |
thread_data* tsd; |
|
while (0 != (tsd = _tsd.remove_first())) |
try |
|
{ |
|
|
|
_tsd.try_lock(); |
|
} |
|
catch(IPCException&) |
|
{ |
|
return; |
|
} |
|
|
|
AutoPtr<thread_data> tsd(_tsd.next(0)); |
|
while(tsd.get()) |
{ | { |
delete tsd; |
_tsd.remove_no_lock(tsd.get()); |
|
tsd.reset(_tsd.next(0)); |
} | } |
//_tsd.empty_list(); |
_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); |
thread_data *tsd ; |
AutoPtr<thread_data> tsd ; |
tsd = _tsd.remove((const void *)key); // may throw an IPC exception |
tsd.reset(_tsd.remove((const void *)key)); // may throw an IPC exception |
delete tsd; |
tsd.reset(); |
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); } |
try { _tsd.insert_first(ntsd.get()); } |
catch(IPCException& e) { e = e; delete ntsd; throw; } |
catch(IPCException& e) { e = e; throw; } |
|
ntsd.release(); |
} | } |
inline PEGASUS_THREAD_RETURN get_exit(void) { return _exit_code; } | inline PEGASUS_THREAD_RETURN get_exit(void) { return _exit_code; } |
inline PEGASUS_THREAD_TYPE self(void) {return pegasus_thread_self(); } | inline PEGASUS_THREAD_TYPE self(void) {return pegasus_thread_self(); } |
|
|
| |
void detach(void); | void detach(void); |
| |
|
// |
|
// Gets the Thread object associated with the caller's thread. |
|
// Note: this may return NULL if no Thread object is associated |
|
// with the caller's thread. |
|
// |
|
static Thread * getCurrent(); // l10n |
|
|
|
// |
|
// Sets the Thread object associated with the caller's thread. |
|
// Note: the Thread object must be placed on the heap. |
|
// |
|
static void setCurrent(Thread * thrd); // l10n |
|
|
|
// |
|
// Gets the AcceptLanguages object associated with the caller's |
|
// Thread. |
|
// Note: this may return NULL if no Thread object, or no |
|
// AcceptLanguages object, is associated with the caller's thread. |
|
// |
|
static AcceptLanguages * getLanguages(); //l10n |
|
|
|
// |
|
// Sets the AcceptLanguages object associated with the caller's |
|
// Thread. |
|
// Note: a Thread object must have been previously associated with |
|
// the caller's thread. |
|
// Note: the AcceptLanguages object must be placed on the heap. |
|
// |
|
static void setLanguages(AcceptLanguages *langs); //l10n |
|
|
|
// |
|
// Removes the AcceptLanguages object associated with the caller's |
|
// Thread. |
|
// |
|
static void clearLanguages(); //l10n |
|
|
private: | private: |
Thread(); | Thread(); |
|
|
|
static Sint8 initializeKey(); // l10n |
|
|
inline void create_tsd(const Sint8 *key ) throw(IPCException) | inline void create_tsd(const Sint8 *key ) throw(IPCException) |
{ | { |
thread_data *tsd = new thread_data(key); |
AutoPtr<thread_data> tsd(new thread_data(key)); |
try { _tsd.insert_first(tsd); } |
_tsd.insert_first(tsd.get()); |
catch(IPCException& e) { e = e; delete tsd; throw; } |
tsd.release(); |
} | } |
PEGASUS_THREAD_HANDLE _handle; | PEGASUS_THREAD_HANDLE _handle; |
Boolean _is_detached; | Boolean _is_detached; |
|
|
void *_thread_parm; | void *_thread_parm; |
PEGASUS_THREAD_RETURN _exit_code; | PEGASUS_THREAD_RETURN _exit_code; |
static Boolean _signals_blocked; | static Boolean _signals_blocked; |
|
static PEGASUS_THREAD_KEY_TYPE _platform_thread_key; //l10n |
|
static Boolean _key_initialized; // l10n |
|
static Boolean _key_error; // l10n |
friend class ThreadPool; | friend class ThreadPool; |
} ; | } ; |
| |
|
|
| |
~ThreadPool(void); | ~ThreadPool(void); |
| |
void allocate_and_awaken(void *parm, |
/** |
|
Allocate and start a thread to do a unit of work. |
|
@param parm A generic parameter to pass to the thread |
|
@param work A pointer to the function that is to be executed by |
|
the thread |
|
@param blocking A pointer to an optional semaphore which, if |
|
specified, is signaled after the thread finishes |
|
executing the work function |
|
@return PEGASUS_THREAD_OK if the thread is started successfully, |
|
PEGASUS_THREAD_INSUFFICIENT_RESOURCES if the |
|
resources necessary to start the thread are not currently |
|
available. PEGASUS_THREAD_SETUP_FAILURE if the thread |
|
could not be setup properly. PEGASUS_THREAD_UNAVAILABLE |
|
if this service is shutting down and no more threads can |
|
be allocated. |
|
@exception IPCException |
|
*/ |
|
ThreadStatus allocate_and_awaken( |
|
void* parm, |
PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *work)(void *), | PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *work)(void *), |
Semaphore *blocking = 0) |
Semaphore* blocking = 0); |
throw(IPCException); |
|
|
|
| |
Uint32 kill_dead_threads( void ) | Uint32 kill_dead_threads( void ) |
throw(IPCException); | throw(IPCException); |
|
|
_deadlock_detect.tv_usec = deadlock.tv_usec; | _deadlock_detect.tv_usec = deadlock.tv_usec; |
} | } |
| |
inline struct timeval * get_deadlock_detect(struct timeval *buffer) const |
|
{ |
|
if(buffer == 0) |
|
throw NullPointer(); |
|
buffer->tv_sec = _deadlock_detect.tv_sec; |
|
buffer->tv_usec = _deadlock_detect.tv_usec; |
|
return buffer; |
|
} |
|
|
|
inline Uint32 running_count(void) | inline Uint32 running_count(void) |
{ | { |
return _running.count(); | return _running.count(); |
|
|
DQueue<Thread> _running; | DQueue<Thread> _running; |
DQueue<Thread> _dead; | DQueue<Thread> _dead; |
AtomicInt _dying; | AtomicInt _dying; |
|
|
static void _sleep_sem_del(void *p); | static void _sleep_sem_del(void *p); |
| |
void _check_deadlock(struct timeval *start) throw(Deadlock); | void _check_deadlock(struct timeval *start) throw(Deadlock); |
Boolean _check_deadlock_no_throw(struct timeval *start); | Boolean _check_deadlock_no_throw(struct timeval *start); |
Boolean _check_dealloc(struct timeval *start); | Boolean _check_dealloc(struct timeval *start); |
Thread *_init_thread(void) throw(IPCException); | Thread *_init_thread(void) throw(IPCException); |
|
void _cleanupThread(Thread* thread); |
void _link_pool(Thread *th) throw(IPCException); | void _link_pool(Thread *th) throw(IPCException); |
static PEGASUS_THREAD_RETURN _undertaker(void *); | static PEGASUS_THREAD_RETURN _undertaker(void *); |
|
static PEGASUS_THREAD_RETURN _graveyard(Thread *); |
static DQueue<ThreadPool> _pools; | static DQueue<ThreadPool> _pools; |
}; | }; |
| |