diff options
-rw-r--r-- | ace/Log_Msg.cpp | 7 | ||||
-rw-r--r-- | ace/Thread_Manager.cpp | 228 | ||||
-rw-r--r-- | ace/Thread_Manager.h | 155 | ||||
-rw-r--r-- | ace/Thread_Manager.i | 96 |
4 files changed, 466 insertions, 20 deletions
diff --git a/ace/Log_Msg.cpp b/ace/Log_Msg.cpp index f9a20ec9fc8..ba38f8560e5 100644 --- a/ace/Log_Msg.cpp +++ b/ace/Log_Msg.cpp @@ -131,6 +131,13 @@ extern "C" void ACE_TSS_cleanup (void *ptr) { +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + // Delegate to thr_desc if this not has terminated + ACE_Log_Msg* log_msg = (ACE_Log_Msg*) ptr; + if (log_msg->thr_desc()!=0) + log_msg->thr_desc()->log_msg_cleanup(log_msg); + else +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ delete (ACE_Log_Msg *) ptr; } #endif /* ACE_MT_SAFE */ diff --git a/ace/Thread_Manager.cpp b/ace/Thread_Manager.cpp index 33db55f6a8e..f9c64b38637 100644 --- a/ace/Thread_Manager.cpp +++ b/ace/Thread_Manager.cpp @@ -49,19 +49,160 @@ ACE_Thread_Descriptor::~ACE_Thread_Descriptor (void) delete this->sync_; } +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) +void ACE_Thread_Descriptor::at_pop(int apply) + +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_pop"); + // Get first at from at_exit_list + ACE_At_Thread_Exit* at = this->at_exit_list_; + // Remove at from at_exit list + this->at_exit_list_ = at->next_; + // Apply if required + if (apply) + { + at->apply(); + // Do the apply method + at->was_applied(1); + // Mark at has been applied to avoid double apply from + // at destructor + } + // If at is not owner delete at. + if (!at->is_owner()) + delete at; +} + +void +ACE_Thread_Descriptor::at_push(ACE_At_Thread_Exit* cleanup, int is_owner) + +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_push"); + cleanup->is_owner(is_owner); + cleanup->td_ = this; + cleanup->next_ = at_exit_list_; + at_exit_list_ = cleanup; +} + +int +ACE_Thread_Descriptor::at_exit(ACE_At_Thread_Exit& cleanup) + +{ + ACE_TRACE("ACE_Thread_Descriptor::at_exit"); + at_push(&cleanup, 1); + return 0; +} + +int +ACE_Thread_Descriptor::at_exit(ACE_At_Thread_Exit* cleanup) + +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); + if (cleanup==0) + return -1; + else + { + this->at_push(cleanup); + return 0; + } +} + +void +ACE_Thread_Descriptor::do_at_exit() + +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); + while (at_exit_list_!=0) + this->at_pop(); +} + +void +ACE_Thread_Descriptor::terminate() + +{ + ACE_TRACE ("ACE_Thread_Descriptor::terminate"); + + if (!terminated_) + { + terminated_ = 1; + // Run at_exit hooks + this->do_at_exit(); + // We must remove Thread_Descriptor from Thread_Manager list + if (this->tm_!=0) + { + int close_handle = 0; + +#if !defined (VXWORKS) + // Threads created with THR_DAEMON shouldn't exist here, but + // just to be safe, let's put it here. + + if (ACE_BIT_DISABLED (this->flags_, (THR_DETACHED | THR_DAEMON)) + || (ACE_BIT_ENABLED (this->flags_, THR_JOINABLE))) + { + // Mark thread as terminated. + this->thr_state_ = ACE_THR_TERMINATED; + tm_->terminated_thr_queue_.enqueue_tail (*this); + // Must copy the information here because td will be "freed" below. + } +#if defined (ACE_WIN32) + else + { + close_handle = 1; + } +#endif /* ACE_WIN32 */ +#endif /* ! VXWORKS */ + + // Remove thread descriptor from the table. + if (this->tm_!=0) + tm_->remove_thr (this, close_handle); + } + + // Check if we need delete ACE_Log_Msg instance + ACE_Log_Msg* log_msg = this->log_msg_; + // If ACE_TSS_cleanup was not executed first log_msg==0 + if (log_msg==0) + { + // Only inform to ACE_TSS_cleanup that it must delete the log instance + // setting ACE_LOG_MSG thr_desc to 0. + ACE_LOG_MSG->thr_desc(0); + } + else + { + // Thread_Descriptor is the owner of the Log_Msg instance!! + // deleted. + this->log_msg_ = 0; + delete log_msg; + } + } +} + +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + int ACE_Thread_Descriptor::at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param) { ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); - - // @@ This should really store these values into a stack, but we're - // just solving one problem at a time now... - this->cleanup_info_.object_ = object; +#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) this->cleanup_info_.cleanup_hook_ = cleanup_hook; + this->cleanup_info_.object_ = object; this->cleanup_info_.param_ = param; +#else + // To keep compatibility, when cleanup_hook is null really is a at_pop + // without apply. + if (cleanup_hook==0) + { + if (this->at_exit_list_!=0) + this->at_pop(0); + } + else + { + ACE_At_Thread_Exit* cleanup; + ACE_NEW_RETURN (cleanup, ACE_At_Thread_Exit_Func(object,cleanup_hook,param), -1); + this->at_push(cleanup); + } return 0; +#endif /* ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ } void @@ -70,26 +211,32 @@ ACE_Thread_Descriptor::dump (void) const ACE_TRACE ("ACE_Thread_Descriptor::dump"); ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_id_ = %d"), this->thr_id_)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_handle_ = %d"), this->thr_handle_)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_state_ = %d"), this->thr_state_)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\ncleanup_info_.cleanup_hook_ = %x"), this->cleanup_info_.cleanup_hook_)); - ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nflags_ = %x\n"), this->flags_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_id_ = %d"), this->thr_id_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_handle_ = %d"), this->thr_handle_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nthr_state_ = %d"), this->thr_state_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\ncleanup_info_.cleanup_hook_ = %x"), this->cleanup_info_.cleanup_hook_)); + ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("\nflags_ = %x\n"), this->flags_)); - ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); } ACE_Thread_Descriptor::ACE_Thread_Descriptor (void) : grp_id_ (0), thr_state_ (ACE_THR_IDLE), +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + at_exit_list_(0), + log_msg_(0), + terminated_(0), +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ task_ (0) { ACE_TRACE ("ACE_Thread_Descriptor::ACE_Thread_Descriptor"); - +#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) this->cleanup_info_.cleanup_hook_ = 0; this->cleanup_info_.object_ = 0; this->cleanup_info_.param_ = 0; +#endif /* ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ ACE_NEW (this->sync_, ACE_DEFAULT_THREAD_MANAGER_LOCK); } @@ -716,12 +863,22 @@ ACE_Thread_Manager::append_thr (ACE_thread_t t_id, thr_desc->grp_id_ = grp_id; thr_desc->thr_state_ = thr_state; thr_desc->task_ = task; +#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) thr_desc->cleanup_info_.cleanup_hook_ = 0; thr_desc->cleanup_info_.object_ = 0; thr_desc->cleanup_info_.param_ = 0; +#else /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + thr_desc->at_exit_list_ = 0; + // Start the at_exit hook list. + thr_desc->tm_ = this; + // Setup the Thread_Manager. +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ thr_desc->flags_ = flags; this->thr_list_.insert_head (thr_desc); +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + thr_desc->terminated_ = 0; +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ thr_desc->registered_ = 1; thr_desc->sync_->release (); @@ -831,6 +988,9 @@ ACE_Thread_Manager::remove_thr (ACE_Thread_Descriptor *td, ACE_thread_t tid = td->self (); #endif /* VXWORKS */ +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + td->tm_ = 0; +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ this->thr_list_.remove (td); #if defined (VXWORKS) @@ -1318,6 +1478,24 @@ ACE_Thread_Manager::wait_grp (int grp_id) return result; } +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) +int +ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit* at) +{ + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + return this->thread_desc_self ()->at_exit (at); +} + +int +ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit& at) +{ + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + return this->thread_desc_self ()->at_exit (at); +} +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + int ACE_Thread_Manager::at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, @@ -1360,6 +1538,7 @@ ACE_Thread_Manager::exit (void *status, int do_thr_exit) } #endif /* ACE_WIN32 */ +#if defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) ACE_Cleanup_Info cleanup_info; // Just hold onto the guard while finding this thread's id and @@ -1422,6 +1601,31 @@ ACE_Thread_Manager::exit (void *status, int do_thr_exit) if (cleanup_info.cleanup_hook_ != 0) (*cleanup_info.cleanup_hook_) (cleanup_info.object_, cleanup_info.param_); +#else /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + // Just hold onto the guard while finding this thread's id and + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + // Find the thread id, but don't use the cache. It might have been + // deleted already. +#if defined (VXWORKS) + ACE_hthread_t id; + ACE_OS::thr_self (id); + ACE_Thread_Descriptor* td = this->find_hthread (id); +#else /* ! VXWORKS */ + ACE_thread_t id = ACE_OS::thr_self (); + ACE_Thread_Descriptor* td = this->find_thread (id); +#endif /* ! VXWORKS */ + if (td != 0) + { + // @@ We call Thread_Descriptor terminate this realize the cleanup + // process itself. + td->terminate(); + } + } + + +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ if (do_thr_exit) { diff --git a/ace/Thread_Manager.h b/ace/Thread_Manager.h index 9e339c29e34..9a855eaddd3 100644 --- a/ace/Thread_Manager.h +++ b/ace/Thread_Manager.h @@ -56,10 +56,10 @@ // This is the synchronization mechanism used to prevent a thread -// descriptor from getting removed from the Thread_Manager before it gets +// descriptor gets removed from the Thread_Manager before it gets // stash into it. If you want to disable this feature (and risk of -// corrupting the freelist,) you have to define the lock as ACE_Null_Mutex. -// Usually, if you are sure that your threads will run for an +// corrupting the freelist,) you define the lock as ACE_Null_Mutex. +// Usually, if you can be sure that your threads will run for an // extended period of time, you can safely disable the lock. #if !defined (ACE_DEFAULT_THREAD_MANAGER_LOCK) @@ -69,6 +69,79 @@ // Forward declarations. class ACE_Task_Base; class ACE_Thread_Manager; +class ACE_Thread_Descriptor; + +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) +class ACE_At_Thread_Exit +{ + // = TITLE + // Contains a method to be applied when a thread is terminated. + friend class ACE_Thread_Descriptor; + friend class ACE_Thread_Manager; +public: + // Default constructor + ACE_At_Thread_Exit(void); + + // The destructor + virtual ~ACE_At_Thread_Exit(void); + + // At_Thread_Exit has the ownership? + int is_owner() const; + + // Set the ownership of the At_Thread_Exit + int is_owner(int owner); + + // This At_Thread_Exit was applied? + int was_applied() const; + + // Set applied state of At_Thread_Exit + int was_applied(int applied); + +protected: + ACE_At_Thread_Exit* next_; + // The next At_Thread_Exit hook in the list. + + // Do the apply if necessary + void do_apply(); + + virtual void apply() = 0; + // The apply method. + + ACE_Thread_Descriptor* td_; + // The Thread_Descriptor where this at is registered. + + int was_applied_; + // The at was applied? + + int is_owner_; + // The at has the ownership of this? +}; + +class ACE_At_Thread_Exit_Func : public ACE_At_Thread_Exit +{ +public: + // Constructor + ACE_At_Thread_Exit_Func(void* object, + ACE_CLEANUP_FUNC func, + void* param = 0); + + virtual ~ACE_At_Thread_Exit_Func (void); + +protected: + void* object_; + // The object to be cleanup + + ACE_CLEANUP_FUNC func_; + // The cleanup func + + void* param_; + // A param if required + + // The apply method + void apply(); +}; + +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ class ACE_Thread_Descriptor_Base { @@ -111,7 +184,9 @@ class ACE_Export ACE_Thread_Descriptor : public ACE_Thread_Descriptor_Base // = TITLE // Information for controlling threads that run under the control // of the <Thread_Manager>. - +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + friend class ACE_At_Thread_Exit; +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ friend class ACE_Thread_Manager; friend class ACE_Double_Linked_List<ACE_Thread_Descriptor>; friend class ACE_Double_Linked_List_Iterator<ACE_Thread_Descriptor>; @@ -139,6 +214,22 @@ public: void dump (void) const; // Dump the state of an object. +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + void log_msg_cleanup(ACE_Log_Msg* log_msg); + // This cleanup function must be called only for ACE_TSS_cleanup. + // The ACE_TSS_cleanup delegate Log_Msg instance destruction when + // Log_Msg cleanup is called before terminate. + + int at_exit (ACE_At_Thread_Exit* cleanup); + // Register an At_Thread_Exit hook and the ownership is acquire by + // Thread_Descriptor, this is the usual case when the AT is dynamically + // allocated. + + int at_exit (ACE_At_Thread_Exit& cleanup); + // Register an At_Thread_Exit hook and the ownership is retained for the + // caller. Normally used when the at_exit hook is created in stack. +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + int at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param); @@ -174,6 +265,29 @@ public: // of g++ couldn't grok this code without it. private: +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + void at_pop(int apply = 1); + // Pop an At_Thread_Exit from at thread termination list, apply the at + // if apply is true. + + void at_push(ACE_At_Thread_Exit* cleanup, int is_owner = 0); + // Push an At_Thread_Exit to at thread termination list and set the + // ownership of at. + + void do_at_exit(); + // Run the AT_Thread_Exit hooks. + + void terminate(); + // terminate realize the cleanup process to thread termination + + ACE_Log_Msg* log_msg_; + // Thread_Descriptor is the ownership of ACE_Log_Msg if log_msg_!=0 + // This can occur because ACE_TSS_cleanup was executed before terminate. + + ACE_At_Thread_Exit* at_exit_list_; + // The AT_Thread_Exit list +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + int grp_id_; // Group ID. @@ -187,7 +301,13 @@ private: ACE_Task_Base *task_; // Pointer to an <ACE_Task_Base> or NULL if there's no - // <ACE_Task_Base>; + // <ACE_Task_Base>. + +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + ACE_Thread_Manager* tm_; + // Pointer to an <ACE_Thread_Manager> or NULL if there's no + // <ACE_Thread_Manager>. +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ ACE_DEFAULT_THREAD_MANAGER_LOCK *sync_; // Registration lock to prevent premature removal of thread descriptor. @@ -195,6 +315,11 @@ private: int registered_; // Keep track of registration status. +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + int terminated_; + // Keep track of termination status. +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + ACE_Thread_Descriptor *next_; ACE_Thread_Descriptor *prev_; // We need these pointers to maintain the double-linked list in a @@ -224,18 +349,21 @@ class ACE_Export ACE_Thread_Manager // The default behavior of thread manager is to wait on // all threads under it's management when it gets destructed. // Therefore, remember to remove a thread from thread manager if - // you don't want it to wait for the thread. There are also - // functions to disable this default wait-on-exit behavior. + // you don't want it to wait for the thread. There are also + // function to disable this default wait-on-exit behavior. // However, if your program depends on turning this off to run // correctly, you are probably doing something wrong. Rule of // thumb, use ACE_Thread to manage your daemon threads. // - // Notice that if there're threads that live beyond the scope of main (), + // Notice that if there're threads live beyond the scope of main (), // you are sure to have resource leaks in your program. Remember // to wait on threads before exiting main() if that could happen // in your programs. public: friend class ACE_Thread_Control; +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + friend class ACE_Thread_Descriptor; +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ #if !defined (__GNUG__) typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int); @@ -486,6 +614,17 @@ public: int set_grp (ACE_Task_Base *task, int grp_id); int get_grp (ACE_Task_Base *task, int &grp_id); +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) + int at_exit (ACE_At_Thread_Exit* cleanup); + // Register an At_Thread_Exit hook and the ownership is acquire by + // Thread_Descriptor, this is the usual case when the AT is dynamically + // allocated. + + int at_exit (ACE_At_Thread_Exit& cleanup); + // Register an At_Thread_Exit hook and the ownership is retained for the + // caller. Normally used when the at_exit hook is created in stack. +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + int at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param); diff --git a/ace/Thread_Manager.i b/ace/Thread_Manager.i index c01207cb2d2..f82ba21bb46 100644 --- a/ace/Thread_Manager.i +++ b/ace/Thread_Manager.i @@ -3,6 +3,93 @@ // Thread_Manager.i +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) +ACE_INLINE +ACE_At_Thread_Exit::ACE_At_Thread_Exit() + : td_(0), + was_applied_(0), + is_owner_(1) + +{ +} + +ACE_INLINE int +ACE_At_Thread_Exit::was_applied() const + +{ + return was_applied_; +} + +ACE_INLINE int +ACE_At_Thread_Exit::was_applied(int applied) + +{ + was_applied_ = applied; + if (was_applied_) + td_ = 0; + return was_applied_; +} + +ACE_INLINE int +ACE_At_Thread_Exit::is_owner() const + +{ + return is_owner_; +} + +ACE_INLINE int +ACE_At_Thread_Exit::is_owner(int owner) + +{ + is_owner_ = owner; + return is_owner_; +} + +ACE_INLINE void +ACE_At_Thread_Exit::do_apply() + +{ + if (!this->was_applied_ && this->is_owner_) + { + td_->at_pop(); + } +} + +ACE_INLINE +ACE_At_Thread_Exit::~ACE_At_Thread_Exit() + +{ + this->do_apply(); +} + +ACE_INLINE +ACE_At_Thread_Exit_Func::ACE_At_Thread_Exit_Func ( + void* object, + ACE_CLEANUP_FUNC func, + void* param +) + : object_(object), + func_(func), + param_(param) + +{ +} + +ACE_INLINE +ACE_At_Thread_Exit_Func::~ACE_At_Thread_Exit_Func() + +{ + this->do_apply(); +} + +ACE_INLINE void +ACE_At_Thread_Exit_Func::apply() + +{ + func_(object_, param_); +} +#endif /* ! ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + ACE_INLINE ACE_Thread_Descriptor_Base::ACE_Thread_Descriptor_Base (void) : thr_id_ (ACE_OS::NULL_thread), @@ -77,6 +164,15 @@ ACE_Thread_Descriptor::flags (void) const return flags_; } +#if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) +ACE_INLINE void +ACE_Thread_Descriptor::log_msg_cleanup(ACE_Log_Msg* log_msg) + +{ + log_msg_ = log_msg; +} +#endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ + // Set the <next_> pointer ACE_INLINE void ACE_Thread_Descriptor::set_next (ACE_Thread_Descriptor *td) |