summaryrefslogtreecommitdiff
path: root/ace
diff options
context:
space:
mode:
Diffstat (limited to 'ace')
-rw-r--r--ace/OS.h1
-rw-r--r--ace/OS.i14
-rw-r--r--ace/Process.cpp7
-rw-r--r--ace/Process.h19
-rw-r--r--ace/Process_Manager.cpp313
-rw-r--r--ace/Process_Manager.h93
-rw-r--r--ace/Thread_Manager.cpp26
-rw-r--r--ace/Thread_Manager.h3
8 files changed, 209 insertions, 267 deletions
diff --git a/ace/OS.h b/ace/OS.h
index dbd8d2f0fd8..6ca40edfdf1 100644
--- a/ace/OS.h
+++ b/ace/OS.h
@@ -2639,6 +2639,7 @@ public:
// NT. argv[0] must be the full path name to the executable.
static gid_t getgid (void);
static pid_t getpid (void);
+ static pid_t getpgid (pid_t pid);
static uid_t getuid (void);
static pid_t setsid (void);
static int system (const char *s);
diff --git a/ace/OS.i b/ace/OS.i
index c598706338d..bcbdd108d09 100644
--- a/ace/OS.i
+++ b/ace/OS.i
@@ -6137,6 +6137,20 @@ ACE_OS::getpid (void)
#endif /* ACE_WIN32 */
}
+ACE_INLINE pid_t
+ACE_OS::getpgid (pid_t pid)
+{
+ // ACE_TRACE ("ACE_OS::getpid");
+#if defined (ACE_WIN32) || defined (CHORUS)
+ return ACE_NOTSUP_RETURN (-1);
+#elif defined (VXWORKS)
+ // getpid() is not supported: just one process anyways
+ return 0;
+#else
+ ACE_OSCALL_RETURN (::getpgid (pid), pid_t, -1);
+#endif /* ACE_WIN32 */
+}
+
ACE_INLINE off_t
ACE_OS::lseek (ACE_HANDLE handle, off_t offset, int whence)
{
diff --git a/ace/Process.cpp b/ace/Process.cpp
index 76d3b5d5710..071d8eabcbb 100644
--- a/ace/Process.cpp
+++ b/ace/Process.cpp
@@ -53,7 +53,6 @@ ACE_Process::~ACE_Process (void)
// Free resources allocated in kernel.
ACE_OS::close (this->process_info_.hThread);
ACE_OS::close (this->process_info_.hProcess);
-
#endif /* ACE_WIN32 */
}
@@ -157,7 +156,7 @@ ACE_Process::start (char *argv[], char *envp[])
return -1;
#else /* ACE_WIN32 */
// Fork the new process.
- this->child_id_ = ACE_OS::fork ();
+ this->child_id_ = ACE_OS::fork (argv == 0 ? "child" : argv[1]);
switch (this->child_id_)
{
@@ -193,9 +192,11 @@ ACE_Process::start (char *argv[], char *envp[])
// If the execv fails, this child needs to exit.
ACE_OS::exit (errno);
}
+ return 0;
+ /* NOTREACHED */
default:
// Server process. The fork succeeded.
- return 0;
+ return this->child_id_;
}
#endif /* ACE_WIN32 */
}
diff --git a/ace/Process.h b/ace/Process.h
index 82cc94d4b40..ac2313ae63b 100644
--- a/ace/Process.h
+++ b/ace/Process.h
@@ -45,15 +45,17 @@ public:
ACE_HANDLE std_err = ACE_INVALID_HANDLE,
char *envp[] = 0);
// Set the standard handles of the new process to the respective
- // handles and start the new process. <argv> must be specified. It
+ // handles and start the new process. If <argv> is non-NULL it
// should be of the following form: argv = {
- // "c:\full\path\to\foo.exe", "-a", "arg1", "etc", 0 } Returns the
- // new process id on success, -1 on failure. If you want to affect
- // a subset of the handles, make sure to set the others to
+ // "c:\full\path\to\foo.exe", "-a", "arg1", "etc", 0 }. If <argv>
+ // is NULL then no <exec> is performed. If <argv> is non-NULL and
+ // <envp> is specified, it is passed as the environment for the new
+ // process, according to the rules for execve(). If you want to
+ // affect a subset of the handles, make sure to set the others to
// ACE_INVALID_HANDLE.
~ACE_Process (void);
- // Death incarnate.
+ // Destructor.
int set_handles (ACE_HANDLE std_in,
ACE_HANDLE std_out = ACE_INVALID_HANDLE,
@@ -67,9 +69,10 @@ public:
// Set the working directory for the process.
pid_t start (char *argv[], char *envp[] = 0);
- // Start the new process. <argv> must be specified. It should be
- // of the following form: argv = { "c:\full\path\to\foo.exe", "-a",
- // "arg1", "etc", 0 }. If <envp> is specified, it is passed as the
+ // Start the new process. If <argv> is non-NULL it should be of the
+ // following form: argv = { "c:\full\path\to\foo.exe", "-a", "arg1",
+ // "etc", 0 }. If <argv> is NULL then no <exec> is performed. If
+ // <argv> is non-NULL and <envp> is specified, it is passed as the
// environment for the new process, according to the rules for
// execve(). Returns the new process id on success, -1 on failure.
diff --git a/ace/Process_Manager.cpp b/ace/Process_Manager.cpp
index 027e5b68fe9..1ee99f29703 100644
--- a/ace/Process_Manager.cpp
+++ b/ace/Process_Manager.cpp
@@ -9,13 +9,35 @@
#include "ace/Process_Manager.i"
#endif /* __ACE_INLINE__ */
-ACE_ALLOC_HOOK_DEFINE(ACE_Process_Control)
ACE_ALLOC_HOOK_DEFINE(ACE_Process_Manager)
void
+ACE_Process_Descriptor::dump (void) const
+{
+ ACE_TRACE ("ACE_Process_Descriptor::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, "\nproc_id_ = %d", this->proc_id_));
+ ACE_DEBUG ((LM_DEBUG, "\ngrp_id_ = %d", this->grp_id_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
ACE_Process_Manager::dump (void) const
{
ACE_TRACE ("ACE_Process_Manager::dump");
+
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, "\nmax_table_size_ = %d", this->max_table_size_));
+ ACE_DEBUG ((LM_DEBUG, "\ncurrent_count_ = %d", this->current_count_));
+
+ for (size_t i = 0; i < this->current_count_; i++)
+ this->proc_table_[i].dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
}
ACE_Process_Descriptor::ACE_Process_Descriptor (void)
@@ -28,7 +50,6 @@ ACE_Process_Manager::resize (size_t size)
{
ACE_TRACE ("ACE_Process_Manager::resize");
- ACE_TRACE ("ACE_Thread_Manager::resize");
ACE_Process_Descriptor *temp;
ACE_NEW_RETURN (temp, ACE_Process_Descriptor[size], -1);
@@ -112,15 +133,27 @@ ACE_Process_Manager::start (char *argv[],
// Create a new process, potentially causing an exec(), as well.
// This API clearly needs to be improved to pass more information
// in...
- pid_t pid = ACE_Process process (argv,
- ACE_INVALID_HANDLE,
- ACE_INVALID_HANDLE,
- ACE_INVALID_HANDLE,
- envp);
- if (pid == -1)
- return -1;
+
+ ACE_Process process;
+
+ process.set_handles (ACE_INVALID_HANDLE,
+ ACE_INVALID_HANDLE,
+ ACE_INVALID_HANDLE);
+
+ pid_t pid = process.start (argv, envp);
+
+ // Only include the pid in the parent's table.
+ if (pid == -1 || pid == 0)
+ return pid;
else
- return this->append_proc (pid);
+ {
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
+
+ if (this->append_proc (pid) == -1)
+ return -1;
+ else
+ return pid;
+ }
}
// Create N new processs running FUNC.
@@ -132,20 +165,26 @@ ACE_Process_Manager::start_n (size_t n,
{
ACE_TRACE ("ACE_Process_Manager::spawn_n");
+#if 0
+ // This doesn't work (yet).
for (size_t i = 0; i < n; i++)
if (this->start (argv, envp) == -1)
return -1;
return 0;
-
+#else
+ ACE_UNUSED_ARG (n);
+ ACE_UNUSED_ARG (argv);
+ ACE_UNUSED_ARG (envp);
+ ACE_NOTSUP_RETURN (-1);
+#endif /* 0 */
}
// Append a process into the pool (does not check for duplicates).
// Must be called with locks held.
int
-ACE_Process_Manager::append_proc (pid_t pid,
- ACE_Process_Descriptor::Process_State proc_state)
+ACE_Process_Manager::append_proc (pid_t pid)
{
ACE_TRACE ("ACE_Process_Manager::append_proc");
@@ -156,12 +195,11 @@ ACE_Process_Manager::append_proc (pid_t pid,
return -1;
else
{
- ACE_Thread_Descriptor &proc_desc =
+ ACE_Process_Descriptor &proc_desc =
this->proc_table_[this->current_count_];
proc_desc.proc_id_ = pid;
- proc_desc.proc_id_ =
- proc_desc.proc_state_ = proc_state;
+ proc_desc.grp_id_ = ACE_OS::getpgid (pid);
this->current_count_++;
return 0;
@@ -172,171 +210,98 @@ ACE_Process_Manager::append_proc (pid_t pid,
// allow them to be inserted twice).
int
-ACE_Process_Manager::insert_proc (pid_t t_id)
+ACE_Process_Manager::insert_proc (pid_t pid)
{
ACE_TRACE ("ACE_Process_Manager::insert_proc");
- return -1;
-}
-
-// Remove a process from the pool. Must be called with locks held.
-
-void
-ACE_Process_Manager::remove_proc (int i)
-{
- ACE_TRACE ("ACE_Process_Manager::remove_proc");
-}
-
-int
-ACE_Process_Manager::resume_proc (int i)
-{
- ACE_TRACE ("ACE_Process_Manager::resume_proc");
- return -1;
-}
-
-int
-ACE_Process_Manager::suspend_proc (int i)
-{
- ACE_TRACE ("ACE_Process_Manager::suspend_proc");
-
- return -1;
-}
-
-int
-ACE_Process_Manager::kill_proc (int i, int signum)
-{
- ACE_TRACE ("ACE_Process_Manager::kill_proc");
-
- return -1;
-}
-
-// Locate the index in the table associated with <t_id>. Must be
-// called with the lock held.
-
-int
-ACE_Process_Manager::find (pid_t t_id)
-{
- ACE_TRACE ("ACE_Process_Manager::find");
- return -1;
-}
-// Suspend a single process.
-
-int
-ACE_Process_Manager::suspend (pid_t t_id)
-{
- ACE_TRACE ("ACE_Process_Manager::suspend");
- return -1;
-}
-
-// Resume a single process.
-
-int
-ACE_Process_Manager::resume (pid_t t_id)
-{
- ACE_TRACE ("ACE_Process_Manager::resume");
- return -1;
-}
-
-// Kill a single process.
-int
-ACE_Process_Manager::kill (pid_t t_id, int signum)
-{
- ACE_TRACE ("ACE_Process_Manager::kill");
- return -1;
-}
-
-// Get group ids for a particular process id.
-
-int
-ACE_Process_Manager::get_grp (pid_t t_id, int &grp_id)
-{
- ACE_TRACE ("ACE_Process_Manager::get_grp");
- return -1;
-}
-
-// Set group ids for a particular process id.
+#if 0
+ // Check for duplicates and bail out if they're already
+ // registered...
+ if (this->find_proc (pid) != -1)
+ return -1;
-int
-ACE_Process_Manager::set_grp (pid_t t_id, int grp_id)
-{
- ACE_TRACE ("ACE_Process_Manager::set_grp");
- return -1;
+ return this->append_proc (pid);
+#else
+ ACE_UNUSED_ARG (pid);
+ ACE_NOTSUP_RETURN (-1);
+#endif
}
-// Suspend a group of processs.
+// Remove a process from the pool. Must be called with locks held.
int
-ACE_Process_Manager::apply_grp (int grp_id,
- PROC_FUNC func,
- int arg)
+ACE_Process_Manager::remove (pid_t pid)
{
- ACE_TRACE ("ACE_Process_Manager::apply_grp");
- return -1;
-}
+ ACE_TRACE ("ACE_Process_Manager::remove");
-int
-ACE_Process_Manager::suspend_grp (int grp_id)
-{
- ACE_TRACE ("ACE_Process_Manager::suspend_grp");
- return -1;
-}
+ ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1));
-// Resume a group of processs.
+ int i = this->find_proc (pid);
-int
-ACE_Process_Manager::resume_grp (int grp_id)
-{
- ACE_TRACE ("ACE_Process_Manager::resume_grp");
- return -1;
-}
+ if (i == -1)
+ return -1;
+ else
+ {
+ this->current_count_--;
-// Kill a group of processs.
+ if (this->current_count_ > 0)
+ // Compact the table by moving the last item into the slot vacated
+ // by the index being removed (this is a structure assignment).
+ this->proc_table_[i] = this->proc_table_[this->current_count_];
-int
-ACE_Process_Manager::kill_grp (int grp_id, int signum)
-{
- ACE_TRACE ("ACE_Process_Manager::kill_grp");
- return -1;
+#if defined (ACE_HAS_THREADS)
+ // Tell all waiters when there are no more threads left in the pool.
+ if (this->current_count_ == 0)
+ this->zero_cond_.broadcast ();
+#endif /* ACE_HAS_THREADS */
+ return 0;
+ }
}
int
-ACE_Process_Manager::apply_all (PROC_FUNC func, int arg)
+ACE_Process_Manager::kill (pid_t pid, int signum)
{
- ACE_TRACE ("ACE_Process_Manager::apply_all");
- return -1;
-}
+ ACE_TRACE ("ACE_Process_Manager::kill_proc");
-// Resume all processs that are suspended.
+ // Check for duplicates and bail out if they're already
+ // registered...
+ int i = this->find_proc (pid);
-int
-ACE_Process_Manager::resume_all (void)
-{
- ACE_TRACE ("ACE_Process_Manager::resume_all");
- return -1;
+ if (i == -1)
+ return -1;
+ else
+ {
+ int result = ACE_OS::kill (this->proc_table_[i].proc_id_,
+ signum);
+
+ if (result == -1)
+ {
+ // We need to save this across calls to remove_thr() since that
+ // call may reset errno.
+ int error = errno;
+
+ this->remove (this->proc_table_[i].proc_id_);
+ errno = error;
+ return -1;
+ }
+ else
+ return 0;
+ }
}
-int
-ACE_Process_Manager::suspend_all (void)
-{
- ACE_TRACE ("ACE_Process_Manager::suspend_all");
- return -1;
-}
+// Locate the index in the table associated with <pid>. Must be
+// called with the lock held.
int
-ACE_Process_Manager::kill_all (int sig)
+ACE_Process_Manager::find_proc (pid_t pid)
{
- ACE_TRACE ("ACE_Process_Manager::kill_all");
- return -1;
-}
+ ACE_TRACE ("ACE_Process_Manager::find_proc");
-// Must be called when process goes out of scope to clean up its table
-// slot.
+ for (size_t i = 0; i < this->current_count_; i++)
+ if (pid == this->proc_table_[i].proc_id_)
+ return i;
-void *
-ACE_Process_Manager::exit (void *status)
-{
- ACE_TRACE ("ACE_Process_Manager::exit");
- return 0;
+ return -1;
}
// Wait for all the processs to exit.
@@ -345,36 +310,30 @@ int
ACE_Process_Manager::wait (ACE_Time_Value *timeout)
{
ACE_TRACE ("ACE_Process_Manager::wait");
- return -1;
-}
-void
-ACE_Process_Control::dump (void) const
-{
- ACE_TRACE ("ACE_Process_Control::dump");
-}
+#if defined (ACE_HAS_THREADS)
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
-// Initialize the process controller.
+ while (this->current_count_ > 0)
+ if (this->zero_cond_.wait (timeout) == -1)
+ return -1;
+#else
+ ACE_UNUSED_ARG (timeout);
+#endif /* ACE_HAS_THREADS */
-ACE_Process_Control::ACE_Process_Control (ACE_Process_Manager *t,
- int insert)
-{
- ACE_TRACE ("ACE_Process_Control::ACE_Process_Control");
+ return 0;
}
-// Automatically kill process on exit.
+// Reap a <SIGCHLD> by calling <ACE_OS::waitpid>.
-ACE_Process_Control::~ACE_Process_Control (void)
+int
+ACE_Process_Manager::reap (pid_t pid, int *stat_loc, int options)
{
- ACE_TRACE ("ACE_Process_Control::~ACE_Process_Control");
-}
+ ACE_TRACE ("ACE_Process_Manager::reap");
-// Exit from process (but clean up first).
+ pid = ACE_OS::waitpid (pid, stat_loc, options);
-void *
-ACE_Process_Control::exit (void *exit_status)
-{
- ACE_TRACE ("ACE_Process_Control::exit");
- return 0;
+ if (pid != -1)
+ this->remove (pid);
+ return pid;
}
-
diff --git a/ace/Process_Manager.h b/ace/Process_Manager.h
index 96896b96a4b..651d236c097 100644
--- a/ace/Process_Manager.h
+++ b/ace/Process_Manager.h
@@ -24,14 +24,6 @@ class ACE_Export ACE_Process_Descriptor
// Information for controlling groups of processs.
{
friend class ACE_Process_Manager;
-public:
- enum Process_State
- {
- IDLE,
- SPAWNED,
- RUNNING,
- TERMINATED
- };
private:
ACE_Process_Descriptor (void);
@@ -42,14 +34,10 @@ private:
gid_t grp_id_;
// Unique group ID.
- Process_State proc_state_;
- // Current state of the process.
+ void dump (void) const;
+ // Dump the state of an object.
};
-// Forward declaration.
-
-class ACE_Process_Control;
-
class ACE_Export ACE_Process_Manager
// = TITLE
// Manages a pool of processs.
@@ -92,17 +80,15 @@ public:
// Block until there are no more processs running or <timeout>
// expires. Returns 0 on success and -1 on failure.
- // = Kill methods (send signals...).
- int kill_all (int signum);
- // Send signum to all stopped processs
int kill (pid_t, int signum);
// Kill a single process.
- int kill_grp (int grp_id, int signum);
- // Kill a group of processs.
- // = Set/get group ids for a particular process id.
- int set_grp (pid_t, int grp_id);
- int get_grp (pid_t, int &grp_id);
+ int remove (pid_t pid);
+ // Remove process <pid> from the table. This is typically called by
+ // a signal handler that has just reaped <SIGCHILD>.
+
+ int reap (pid_t pid = -1, int *stat_loc = 0, int options = WNOHANG);
+ // Reap a <SIGCHLD> by calling <ACE_OS::waitpid>.
void dump (void) const;
// Dump the state of an object.
@@ -114,7 +100,7 @@ private:
int resize (size_t);
// Resize the pool of Process_Descriptors.
- int find (pid_t p_id);
+ int find_proc (pid_t p_id);
// Locate the index of the table slot occupied by <p_id>. Returns
// -1 if <p_id> is not in the table doesn't contain <p_id>.
@@ -122,27 +108,10 @@ private:
// Insert a process in the table (checks for duplicates).
// Omitting the process handle won't work on Win32...
- int append_proc (pid_t p_id, ACE_Process_Descriptor::Process_State);
+ int append_proc (pid_t p_id);
// Append a process in the table (adds at the end, growing the table
// if necessary).
- void remove_proc (int i);
- // Remove process from the table.
-
- // = The following four methods implement a simple scheme for
- // operating on a collection of processs atomically.
-
- typedef int (ACE_Process_Manager::*PROC_FUNC)(int, int);
-
- int apply_grp (int grp_id, PROC_FUNC, int = 0);
- // Apply <func> to all members of the table that match the <grp_id>.
-
- int apply_all (PROC_FUNC, int = 0);
- // Apply <func> to all members of the table.
-
- int kill_proc (int i, int signum);
- // Send signal <signum> to the process at index <i>.
-
ACE_Process_Descriptor *proc_table_;
// Vector that describes process state within the Process_Manager.
@@ -152,44 +121,12 @@ private:
size_t current_count_;
// Current number of processs we are managing.
-};
-
-class ACE_Export ACE_Process_Control
- // = TITLE
- // Used to keep track of a process's activities within its entry
- // point function.
-{
-public:
- ACE_Process_Control (ACE_Process_Manager *tm, int insert = 0);
- // Initialize the process control object. If INSERT != 0, then
- // register the process with the ProcessManager.
-
- ~ACE_Process_Control (void);
- // Implicitly kill the process on exit and remove it from its
- // associated ProcessManager.
-
- void *exit (void *status);
- // Explicitly kill the process on exit and remove it from its
- // associated ProcessManager.
-
- void *status (void *status);
- // Set the exit status (and return existing status).
-
- void *status (void);
- // Get the current exit status.
-
- void dump (void) const;
- // Dump the state of an object.
-
- ACE_ALLOC_HOOK_DECLARE;
- // Declare the dynamic allocation hooks.
-
-private:
- ACE_Process_Manager *tm_;
- // Pointer to the process manager for this block of code.
- void *status_;
- // Keeps track of the exit status for the process.
+ // = ACE_Thread_Mutex and condition variable for synchronizing termination.
+#if defined (ACE_HAS_THREADS)
+ ACE_Thread_Mutex lock_;
+ ACE_Condition_Thread_Mutex zero_cond_;
+#endif /* ACE_HAS_THREADS */
};
#if defined (__ACE_INLINE__)
diff --git a/ace/Thread_Manager.cpp b/ace/Thread_Manager.cpp
index 4ea8f97baf0..686d24afef0 100644
--- a/ace/Thread_Manager.cpp
+++ b/ace/Thread_Manager.cpp
@@ -15,6 +15,30 @@ void
ACE_Thread_Manager::dump (void) const
{
ACE_TRACE ("ACE_Thread_Manager::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, "\ngrp_id_ = %d", this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG, "\nmax_table_size_ = %d", this->max_table_size_));
+ ACE_DEBUG ((LM_DEBUG, "\ncurrent_count_ = %d", this->current_count_));
+
+ for (size_t i = 0; i < this->current_count_; i++)
+ this->thr_table_[i].dump ();
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
+}
+
+void
+ACE_Thread_Descriptor::dump (void) const
+{
+ ACE_TRACE ("ACE_Thread_Descriptor::dump");
+ ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
+
+ ACE_DEBUG ((LM_DEBUG, "\nthr_id_ = %d", this->thr_id_));
+ ACE_DEBUG ((LM_DEBUG, "\nthr_handle_ = %d", this->thr_handle_));
+ ACE_DEBUG ((LM_DEBUG, "\ngrp_id_ = %d", this->grp_id_));
+ ACE_DEBUG ((LM_DEBUG, "\nthr_state_ = %d", this->thr_state_));
+
+ ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
}
ACE_Thread_Descriptor::ACE_Thread_Descriptor (void)
@@ -225,7 +249,7 @@ ACE_Thread_Manager::spawn (ACE_THR_FUNC func,
// Create N new threads running FUNC.
int
-ACE_Thread_Manager::spawn_n (int n,
+ACE_Thread_Manager::spawn_n (size_t n,
ACE_THR_FUNC func,
void *args,
long flags,
diff --git a/ace/Thread_Manager.h b/ace/Thread_Manager.h
index 83a5528d279..ccba91ad235 100644
--- a/ace/Thread_Manager.h
+++ b/ace/Thread_Manager.h
@@ -50,6 +50,9 @@ public:
ACE_Task_Base *task_;
// Pointer to an ACE_Task;
+ void dump (void) const;
+ // Dump the state of an object.
+
private:
ACE_thread_t thr_id_;