summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ace/Log_Msg.cpp7
-rw-r--r--ace/Thread_Manager.cpp228
-rw-r--r--ace/Thread_Manager.h155
-rw-r--r--ace/Thread_Manager.i96
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)