version 1.1.2.1, 2001/07/30 12:06:14
|
version 1.69, 2009/08/13 13:13:07
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%LICENSE//////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM |
// Licensed to The Open Group (TOG) under one or more contributor license |
|
// agreements. Refer to the OpenPegasusNOTICE.txt file distributed with |
|
// this work for additional information regarding copyright ownership. |
|
// Each contributor licenses this file to you under the OpenPegasus Open |
|
// Source License; you may not use this file except in compliance with the |
|
// License. |
// | // |
// 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 |
// of this software and associated documentation files (the "Software"), to |
// copy of this software and associated documentation files (the "Software"), |
// deal in the Software without restriction, including without limitation the |
// to deal in the Software without restriction, including without limitation |
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
// the rights to use, copy, modify, merge, publish, distribute, sublicense, |
// sell copies of the Software, and to permit persons to whom the Software is |
// and/or sell copies of the Software, and to permit persons to whom the |
// furnished to do so, subject to the following conditions: |
// Software is furnished to do so, subject to the following conditions: |
// |
|
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN |
|
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED |
|
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT |
|
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
// | // |
//============================================================================== |
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
// | // |
// Author: Mike Day (mdday@us.ibm.com) |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
// | // |
// Modified By: Markus Mueller |
////////////////////////////////////////////////////////////////////////// |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
#ifndef Pegasus_Thread_h | #ifndef Pegasus_Thread_h |
#define Pegasus_Thread_h | #define Pegasus_Thread_h |
| |
#include <Pegasus/Common/IPC.h> |
#include <cstring> |
#include <Pegasus/Common/Config.h> | #include <Pegasus/Common/Config.h> |
#include <Pegasus/Common/Exception.h> |
#include <Pegasus/Common/AtomicInt.h> |
#include <Pegasus/Common/DQueue.h> |
#include <Pegasus/Common/InternalException.h> |
|
#include <Pegasus/Common/AcceptLanguageList.h> |
|
#include <Pegasus/Common/Linkage.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> |
|
#include <Pegasus/Common/Threads.h> |
|
|
|
#if defined(PEGASUS_HAVE_PTHREADS) |
|
# include <signal.h> |
|
#endif |
| |
PEGASUS_NAMESPACE_BEGIN | PEGASUS_NAMESPACE_BEGIN |
| |
class PEGASUS_EXPORT 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), |
~cleanup_handler() ; |
_arg(arg) |
|
{ |
|
} |
|
~cleanup_handler() |
|
{; |
|
} |
| |
private: | private: |
void execute(void) { _routine(_arg); } |
|
|
void execute() |
|
{ |
|
_routine(_arg); |
|
} |
|
|
cleanup_handler(); | cleanup_handler(); |
|
|
void (*_routine)(void *); | void (*_routine)(void *); |
inline Boolean operator==(void *key) { if(key == (void *)_routine) return true; return false; } |
|
void *_arg; | void *_arg; |
PEGASUS_CLEANUP_HANDLE _cleanup_buffer; |
|
friend class Dqueue; |
|
friend class Thread; | friend class Thread; |
}; | }; |
| |
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// |
| |
class PEGASUS_EXPORT SimpleThread |
enum TSD_Key |
{ | { |
|
TSD_ACCEPT_LANGUAGES, |
|
TSD_SLEEP_SEM, |
|
TSD_LAST_ACTIVITY_TIME, |
|
TSD_WORK_FUNC, |
|
TSD_WORK_PARM, |
|
TSD_BLOCKING_SEM, |
|
TSD_CIMOM_HANDLE_CONTENT_LANGUAGES, |
|
TSD_RESERVED_1, |
|
TSD_RESERVED_2, |
|
TSD_RESERVED_3, |
|
TSD_RESERVED_4, |
|
TSD_RESERVED_5, |
|
TSD_RESERVED_6, |
|
TSD_RESERVED_7, |
|
TSD_RESERVED_8, |
|
// Add new TSD keys before this line. |
|
TSD_COUNT |
|
}; |
| |
|
class thread_data |
|
{ |
|
/** |
|
* This class is NOT build thread-safe. |
|
* The Caller(user) of this class has to ensure there is no collision |
|
* taking place. |
|
* |
|
* There is no mechanism in place to protect threads from manipulating |
|
* the same thread-specific storage at one time. |
|
* Make sure the possibility for a parallel access to the same |
|
* threads-specific data from multiple threads cannot arise. |
|
* |
|
* In OpenPegasus this class is used in the ThreadPool |
|
* - on initialisation and creation of threads owned by ThreadPool |
|
* - on threads that are idle inside the ThreadPool |
|
* - on the ThreadPools main thread (the thread which the ThreadPool |
|
* runs in) |
|
* In OpenPegasus this class is used in the |
|
* ClientCIMOMHandleRep and InternalCIMOMHandleRep |
|
* - on the current active Thread which belongs to that CIMOMHandle |
|
* |
|
*/ |
public: | public: |
SimpleThread( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *start )(void *), |
|
void *parameter, Boolean detached ); |
|
|
|
~SimpleThread(); |
|
|
|
void run(void); |
|
|
|
Uint32 threadId(void); |
|
|
|
// get the user parameter |
|
void *get_parm(void); |
|
|
|
// cancellation must be deferred (not asynchronous) |
|
// for user-level threads the thread itself can decide |
|
// when it should die. |
|
void cancel(void); |
|
|
|
void kill(int signum); |
|
|
|
// cancel if there is a pending cancellation request |
|
void test_cancel(void); |
|
|
|
// for user-level threads - put the calling thread |
|
// to sleep and jump to the thread scheduler. |
|
// platforms with preemptive scheduling and native threads |
|
// can define this to be a no-op. |
|
// platforms without preemptive scheduling like NetWare |
|
// or gnu portable threads will have an existing |
|
// routine that can be mapped to this method |
|
|
|
void thread_switch(void); |
|
|
|
// suspend this thread |
|
void suspend(void) ; |
|
|
|
// resume this thread |
|
void resume(void) ; |
|
| |
void sleep(Uint32 msec) ; |
static void default_delete(void *data) |
|
{ |
// block the calling thread until this thread terminates |
if (data) |
void join( PEGASUS_THREAD_RETURN *ret_val); |
::operator delete(data); |
|
} |
|
|
// stack of functions to be called when thread terminates |
|
// will be called last in first out (LIFO) |
|
void cleanup_push( void (*routine) (void *), void *parm ); |
|
void cleanup_pop(Boolean execute) ; |
|
|
|
PEGASUS_THREAD_TYPE self(void) ; |
|
|
|
private: |
|
SimpleThread(); |
|
|
|
PEGASUS_THREAD_HANDLE _handle; |
|
Boolean _is_detached; |
|
Boolean _cancel_enabled; |
|
Boolean _cancelled; |
|
| |
//PEGASUS_SEM_HANDLE _suspend_count; |
thread_data(TSD_Key key) : _delete_func(0), _data(0), _size(0), _key(key) |
Semaphore _suspend; |
{ |
|
} |
| |
// always pass this * as the void * parameter to the thread |
thread_data(TSD_Key key, size_t size) : |
// store the user parameter in _thread_parm |
_delete_func(default_delete), _size(size), _key(key) |
|
{ |
|
_data = ::operator new(_size); |
|
} |
| |
PEGASUS_THREAD_RETURN ( PEGASUS_THREAD_CDECL *_start)(void *) ; |
thread_data(TSD_Key key, size_t size, void* data) |
|
: _delete_func(default_delete), _size(size), _key(key) |
|
{ |
|
_data = ::operator new(_size); |
|
memcpy(_data, data, size); |
|
} |
| |
void *_thread_parm; |
~thread_data() |
} ; |
{ |
|
if (_data && _delete_func) |
|
(*_delete_func)(_data); |
|
} |
| |
/////////////////////////////////////////////////////////////////////////////// |
/** |
|
* 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. |
|
* |
|
* @exception NullPointer |
|
*/ |
|
void put_data(void (*del)(void *), size_t size, void* data) |
|
{ |
|
if (_data && _delete_func) |
|
(*_delete_func)(_data); |
| |
static void default_delete(void * data) { delete [] (char *) data; } |
_delete_func = del; |
|
_data = data; |
|
_size = size; |
|
} |
| |
class PEGASUS_EXPORT thread_data |
size_t get_size() |
{ | { |
|
return _size; |
|
} |
| |
public: |
void* get_data() |
thread_data( Sint8 *key ) : _delete_func(NULL) , _data(NULL) |
|
{ | { |
_key = strdup(key) ; |
return _data; |
} | } |
| |
thread_data(Sint8 *key, int 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) |
{ | { |
_delete_func = default_delete; |
if (data == 0 || size == 0) |
_data = new char [size]; |
throw NullPointer(); |
|
|
|
*data = _data; |
|
*size = _size; |
} | } |
| |
thread_data(Sint8 *key, int size, void *data) |
// @exception NullPointer |
|
void copy_data(void** buf, size_t* size) |
{ | { |
_delete_func = default_delete; |
if ((buf == 0) || (size == 0)) |
_data = new char [size]; |
throw NullPointer(); |
memcpy(_data, data, size); |
|
|
*buf = ::operator new(_size); |
|
*size = _size; |
|
memcpy(*buf, _data, _size); |
} | } |
| |
~thread_data() { if( _data != NULL) _delete_func( _data ); } |
|
| |
void *get_data(Sint8 *key); |
|
void *put_data(Sint8 *key, void (*delete_func) (void *), void *data ) |
|
{ |
|
void *old_data = data; |
|
_delete_func = delete_func; |
|
_data = data; |
|
return(old_data); |
|
} |
|
private: | private: |
inline Boolean operator ==(void *key) ; |
|
void (*_delete_func) (void *data) ; |
|
thread_data(); | thread_data(); |
|
thread_data(const thread_data& x); |
|
thread_data& operator=(const thread_data& x); |
|
|
|
void (*_delete_func)(void*); |
void *_data; | void *_data; |
Sint8 *_key; |
size_t _size; |
friend class Dqueue; |
TSD_Key _key; |
friend class Thread; |
|
}; | }; |
| |
| |
class PEGASUS_EXPORT 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. */ |
|
}; |
|
|
|
/////////////////////////////////////////////////////////////////////////// |
| |
|
class PEGASUS_COMMON_LINKAGE Thread : public Linkable |
|
{ |
public: | public: |
Thread( PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *start )(void *), |
|
void *parameter, Boolean detached ); |
Thread( |
|
ThreadReturnType(PEGASUS_THREAD_CDECL* start) (void*), |
|
void* parameter, |
|
Boolean detached); |
| |
~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 |
void *get_parm(void); |
void *get_parm() |
|
{ |
// send the thread a signal -- may not be appropriate due to Windows |
return _thread_parm; |
void kill(int signum); |
} |
| |
// cancellation must be deferred (not asynchronous) | // cancellation must be deferred (not asynchronous) |
// for user-level threads the thread itself can decide | // for user-level threads the thread itself can decide |
// when it should die. | // when it should die. |
void cancel(void); |
void cancel(); |
|
|
// cancel if there is a pending cancellation request |
|
void test_cancel(void); |
|
| |
// for user-level threads - put the calling thread | // for user-level threads - put the calling thread |
// to sleep and jump to the thread scheduler. | // to sleep and jump to the thread scheduler. |
|
|
// or gnu portable threads will have an existing | // or gnu portable threads will have an existing |
// routine that can be mapped to this method | // routine that can be mapped to this method |
| |
void thread_switch(void); |
void thread_switch(); |
|
|
// suspend this thread |
|
void suspend(void) ; |
|
| |
// resume this thread |
static void sleep(Uint32 msec); |
void resume(void) ; |
|
|
|
void sleep(Uint32 msec) ; |
|
| |
// block the calling thread until this thread terminates | // block the calling thread until this thread terminates |
void join(void ); |
void join(); |
| |
|
// thread routine needs to call this function when |
|
// it is ready to exit |
|
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) |
void cleanup_push( void (*routine) (void *), void *parm ) throw(IPCException); |
void cleanup_push(void (*routine) (void *), void* parm); |
void cleanup_pop(Boolean execute = true) throw(IPCException); |
|
| |
// thread specific data (thread_data object methods) |
void cleanup_pop(Boolean execute = true); |
| |
void create_tsd(void *key ) ; |
// get the buffer associated with the key |
void create_tsd(void *key, int size) ; |
// NOTE: this call leaves the tsd LOCKED !!!! |
void *get_tsd(void *key); |
void* reference_tsd(TSD_Key key) |
void delete_tsd(void *key); |
{ |
void * put_tsd(void *key, void (*delete_func)(void *), void *value); |
if (_tsd[key]) |
|
return _tsd[key]->get_data(); |
|
else |
|
return 0; |
|
} |
| |
inline PEGASUS_THREAD_RETURN get_exit(void) { return _exit_code; } |
// release the lock held on the tsd |
inline PEGASUS_THREAD_TYPE self(void) {return _handle.thid; } |
// NOTE: assumes a corresponding and prior call to reference_tsd() !!! |
|
void dereference_tsd() |
|
{ |
|
} |
| |
private: |
// delete the tsd associated with the key |
Thread(); |
void delete_tsd(TSD_Key key) |
|
{ |
|
thread_data* tsd; |
| |
PEGASUS_THREAD_HANDLE _handle; |
tsd = _tsd[key]; |
Boolean _is_detached; |
_tsd[key] = 0; |
Boolean _cancel_enabled; |
|
Boolean _cancelled; |
|
| |
PEGASUS_SEM_HANDLE _suspend_count; |
if (tsd) |
|
delete tsd; |
|
} |
| |
// always pass this * as the void * parameter to the thread |
void empty_tsd() |
// store the user parameter in _thread_parm |
{ |
|
thread_data* data[TSD_COUNT]; |
| |
PEGASUS_THREAD_RETURN ( PEGASUS_THREAD_CDECL *_start)(void *) ; |
memcpy(data, _tsd, sizeof(_tsd)); |
|
memset(_tsd, 0, sizeof(_tsd)); |
| |
DQueue<cleanup_handler> _cleanup; |
for (size_t i = 0; i < TSD_COUNT; i++) |
DQueue<thread_data> _tsd; |
{ |
void *_thread_parm; |
if (data[i]) |
|
delete data[i]; |
|
} |
|
} |
|
|
|
// create or re-initialize tsd associated with the key |
|
// if the tsd already exists, delete the existing buffer |
|
void put_tsd( |
|
TSD_Key key, |
|
void (*delete_func)(void*), |
|
Uint32 size, |
|
void* value) |
|
{ |
|
thread_data* tsd = new thread_data(key); |
|
tsd->put_data(delete_func, size, value); |
| |
PEGASUS_THREAD_RETURN _exit_code; |
thread_data* old; |
| |
} ; |
old = _tsd[key]; |
|
_tsd[key] = tsd; |
| |
|
if (old) |
|
delete old; |
|
} |
| |
#if 0 |
ThreadReturnType get_exit() |
class PEGASUS_EXPORT Aggregator { |
{ |
|
return _exit_code; |
|
} |
| |
public: |
ThreadType self() |
|
{ |
|
return Threads::self(); |
|
} |
| |
Aggregator(); |
ThreadHandle getThreadHandle() |
~Aggregator(); |
{ |
|
return _handle; |
|
} |
| |
void started(void); |
Boolean isDetached() |
void completed(void); |
{ |
void remaining(int operations); |
return _is_detached; |
void put_result(CIMReference *ref); |
} |
|
|
|
void detach(); |
|
|
|
// |
|
// 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(); |
|
|
|
// |
|
// 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); |
|
|
|
// |
|
// Gets the AcceptLanguageList object associated with the caller's |
|
// Thread. |
|
// Note: this may return NULL if no Thread object, or no |
|
// AcceptLanguageList object, is associated with the caller's thread. |
|
// |
|
static AcceptLanguageList* getLanguages(); |
|
|
|
// |
|
// Sets the AcceptLanguageList object associated with the caller's |
|
// Thread. |
|
// Note: a Thread object must have been previously associated with |
|
// the caller's thread. |
|
// |
|
static void setLanguages(const AcceptLanguageList& langs); |
|
|
|
// |
|
// Removes the AcceptLanguageList object associated with the caller's |
|
// Thread. |
|
// |
|
static void clearLanguages(); |
| |
private: | private: |
int _reference_count; |
Thread(); |
|
|
|
static Sint8 initializeKey(); |
| |
// keep track of the thread running this operation so we can kill |
ThreadHandle _handle; |
// it if necessary |
Boolean _is_detached; |
Thread _owner; |
Boolean _cancelled; |
|
|
// this is a phased aggregate. when it is complete is will |
// always pass this * as the void * parameter to the thread |
// be streamed to the client regardless of the state of |
// store the user parameter in _thread_parm |
// siblings |
|
Boolean _is_phased; |
ThreadReturnType(PEGASUS_THREAD_CDECL* _start) (void *); |
|
List<cleanup_handler, Mutex> _cleanup; |
int _total_values; |
thread_data* _tsd[TSD_COUNT]; |
int _completed_values; |
|
int _total_child_values; |
void* _thread_parm; |
int _completed_child_values; |
ThreadReturnType _exit_code; |
int _completion_state; |
static Boolean _signals_blocked; |
struct timeval _last_update; |
static TSDKeyType _platform_thread_key; |
time_t lifetime; |
static Boolean _key_initialized; |
Aggregator *_parent; |
static Boolean _key_error; |
// children may be phased or not phased |
|
DQueue _children; |
|
// empty results that are filled by provider |
|
DQueue _results; |
|
// array of predicates for events and |
|
// stored queries (cursors) |
|
Array _filter; |
|
} ; | } ; |
#endif |
|
| |
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |
| |