summaryrefslogtreecommitdiff
path: root/linuxthreads_db
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1999-11-03 06:13:09 +0000
committerUlrich Drepper <drepper@redhat.com>1999-11-03 06:13:09 +0000
commitab86fbb1d2866df567219904982dac61751808e5 (patch)
tree7ef290b73205d2a02ca808b585984d6c562857b0 /linuxthreads_db
parentdbd3e8629f6efb51bcddbd9e85ab87c0dd95a6ee (diff)
Update.
* internals.h: Declare __pthread_last_event. * manager.c: Define __pthread_last_event. (pthread_handle_create): Set __pthread_last_event. (pthread_exited): Likewise. * join.c (pthread_exit): Likewise.
Diffstat (limited to 'linuxthreads_db')
-rw-r--r--linuxthreads_db/ChangeLog21
-rw-r--r--linuxthreads_db/Makefile4
-rw-r--r--linuxthreads_db/td_ta_clear_event.c49
-rw-r--r--linuxthreads_db/td_ta_event_getmsg.c124
-rw-r--r--linuxthreads_db/td_ta_new.c20
-rw-r--r--linuxthreads_db/td_ta_set_event.c14
-rw-r--r--linuxthreads_db/td_ta_thr_iter.c110
-rw-r--r--linuxthreads_db/td_thr_clear_event.c35
-rw-r--r--linuxthreads_db/td_thr_get_info.c3
-rw-r--r--linuxthreads_db/td_thr_set_event.c17
-rw-r--r--linuxthreads_db/thread_db.h10
-rw-r--r--linuxthreads_db/thread_dbP.h6
12 files changed, 351 insertions, 62 deletions
diff --git a/linuxthreads_db/ChangeLog b/linuxthreads_db/ChangeLog
index 723f9a4650..0922e9ed24 100644
--- a/linuxthreads_db/ChangeLog
+++ b/linuxthreads_db/ChangeLog
@@ -1,5 +1,26 @@
1999-11-02 Ulrich Drepper <drepper@cygnus.com>
+ * td_ta_thr_iter.c (td_ta_thr_iter): Optimize a bit. Read all
+ handles at once.
+
+ * thread_dbP.h (struct th_thragent): Add pthread_handle_num.
+ * td_ta_new.c: Initialize pthread_handle_num.
+ * td_ta_event_getmsg.c: If last event was already reported search
+ for another unreported event.
+
+ * td_thr_get_info.c (td_thr_get_info): Initialize ti_events.
+
+ * Makefile (libthread_db-routines): Add td_ta_set_event,
+ td_ta_event_getmsg, and td_ta_clear_event.
+ * td_ta_clear_event.c: New file.
+ * td_ta_event_getmsg.c: New file.
+ * td_ta_new.c: Get address of __pthread_last_event in target.
+ * td_ta_set_event.c: Don't overwrite old mask, set additional bits.
+ * td_thr_set_event.c: Likewise.
+ * td_thr_clear_event.c: Implement.
+ * thread_db.h: Declare td_ta_clear_event and td_ta_event_getmsg.
+ * thread_dbP.h (struct td_thragent): Add pthread_last_event.
+
* td_ta_new.c: Don't test for __pthread_threads_debug. Get address
of __pthread_threads_events and fail if this is not possible.
* td_ta_event_addr.c: Implement.
diff --git a/linuxthreads_db/Makefile b/linuxthreads_db/Makefile
index fb2825cffb..fa6b3bca5f 100644
--- a/linuxthreads_db/Makefile
+++ b/linuxthreads_db/Makefile
@@ -37,7 +37,9 @@ libthread_db-routines = td_init td_log td_ta_delete td_ta_get_nthreads \
td_ta_setconcurrency td_ta_enable_stats \
td_ta_reset_stats td_ta_get_stats td_ta_event_addr \
td_thr_event_enable td_thr_set_event \
- td_thr_clear_event td_thr_event_getmsg
+ td_thr_clear_event td_thr_event_getmsg \
+ td_ta_set_event td_ta_event_getmsg \
+ td_ta_clear_event
libthread_db-inhibit-o = $(filter-out .os,$(object-suffixes))
diff --git a/linuxthreads_db/td_ta_clear_event.c b/linuxthreads_db/td_ta_clear_event.c
new file mode 100644
index 0000000000..ec7770eae1
--- /dev/null
+++ b/linuxthreads_db/td_ta_clear_event.c
@@ -0,0 +1,49 @@
+/* Globally disable events.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_clear_event (ta, event)
+ const td_thragent_t *ta;
+ td_thr_events_t *event;
+{
+ td_thr_events_t old_event;
+ int i;
+
+ LOG (__FUNCTION__);
+
+ /* Write the new value into the thread data structure. */
+ if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Remove the set bits in. */
+ for (i = 0; i < TD_EVENTSIZE; ++i)
+ old_event.event_bits[i] &= ~event->event_bits[i];
+
+ /* Write the new value into the thread data structure. */
+ if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ return TD_OK;
+}
diff --git a/linuxthreads_db/td_ta_event_getmsg.c b/linuxthreads_db/td_ta_event_getmsg.c
new file mode 100644
index 0000000000..6b56e0d5e7
--- /dev/null
+++ b/linuxthreads_db/td_ta_event_getmsg.c
@@ -0,0 +1,124 @@
+/* Retrieve event.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "thread_dbP.h"
+
+
+td_err_e
+td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg)
+{
+ /* XXX I cannot think of another way but using a static variable. */
+ static td_thrhandle_t th;
+ td_eventbuf_t event;
+ psaddr_t addr;
+
+ LOG (__FUNCTION__);
+
+ /* Get the pointer to the thread descriptor with the last event. */
+ if (ps_pdread (ta->ph, ta->pthread_last_event,
+ &addr, sizeof (void *)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* If the pointer is NULL no event occurred. */
+ if (addr == 0)
+ return TD_NOMSG;
+
+ /* Read the even structure from the target. */
+ if (ps_pdread (ta->ph,
+ ((char *) addr
+ + offsetof (struct _pthread_descr_struct, p_eventbuf)),
+ &event, sizeof (td_eventbuf_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Check whether an event occurred. */
+ if (event.eventnum == TD_EVENT_NONE)
+ {
+ /* Oh well, this means the last event was already read. So
+ we have to look for any other event. */
+ struct pthread_handle_struct handles[ta->pthread_threads_max];
+ int num;
+ int i;
+
+ /* Read the number of currently active threads. */
+ if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int))
+ != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Now read the handles. */
+ if (ps_pdread (ta->ph, ta->handles, handles,
+ ta->pthread_threads_max * sizeof (handles[0])) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ for (i = 0; i < ta->pthread_threads_max && num > 0; ++i)
+ {
+ if (handles[i].h_descr == NULL)
+ /* No entry here. */
+ continue;
+
+ /* First count this active thread. */
+ --num;
+
+ if (handles[i].h_descr == addr)
+ /* We already handled this. */
+ continue;
+
+ /* Read the event data for this thread. */
+ if (ps_pdread (ta->ph,
+ ((char *) handles[i].h_descr
+ + offsetof (struct _pthread_descr_struct,
+ p_eventbuf)),
+ &event, sizeof (td_eventbuf_t)) != PS_OK)
+ return TD_ERR;
+
+ if (event.eventnum != TD_EVENT_NONE)
+ {
+ /* We found a thread with an unreported event. */
+ addr = handles[i].h_descr;
+ break;
+ }
+ }
+
+ /* If we haven't found any other event signal this to the user. */
+ if (event.eventnum == TD_EVENT_NONE)
+ return TD_NOMSG;
+ }
+
+ /* Generate the thread descriptor. */
+ th.th_ta_p = (td_thragent_t *) ta;
+ th.th_unique = addr;
+
+ /* Fill the user's data structure. */
+ msg->event = event.eventnum;
+ msg->th_p = &th;
+ msg->msg.data = (uintptr_t) event.eventdata;
+
+ /* And clear the event message in the target. */
+ memset (&event, '\0', sizeof (td_eventbuf_t));
+ if (ps_pdwrite (ta->ph,
+ ((char *) addr
+ + offsetof (struct _pthread_descr_struct, p_eventbuf)),
+ &event, sizeof (td_eventbuf_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ return TD_OK;
+}
diff --git a/linuxthreads_db/td_ta_new.c b/linuxthreads_db/td_ta_new.c
index eeaf0cbf51..65535f8d14 100644
--- a/linuxthreads_db/td_ta_new.c
+++ b/linuxthreads_db/td_ta_new.c
@@ -51,15 +51,29 @@ td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
/* Remember the address. */
(*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr;
- /* See whether the library contains the necessary symbols. */
- if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, "__pthread_handles",
- &addr) != PS_OK)
+ /* Get the pointer to the variable pointing to the thread descriptor
+ with the last event. */
+ if (ps_pglobal_lookup (ps, LIBPTHREAD_SO,
+ "__pthread_last_event",
+ &(*ta)->pthread_last_event) != PS_OK)
{
free_return:
free (*ta);
return TD_ERR;
}
+ /* Get the pointer to the variable containing the number of active
+ threads. */
+ if (ps_pglobal_lookup (ps, LIBPTHREAD_SO,
+ "__pthread_handles_num",
+ &(*ta)->pthread_handles_num) != PS_OK)
+ goto free_return;
+
+ /* See whether the library contains the necessary symbols. */
+ if (ps_pglobal_lookup (ps, LIBPTHREAD_SO, "__pthread_handles",
+ &addr) != PS_OK)
+ goto free_return;
+
(*ta)->handles = (struct pthread_handle_struct *) addr;
diff --git a/linuxthreads_db/td_ta_set_event.c b/linuxthreads_db/td_ta_set_event.c
index 10adbdf04f..f783d7567e 100644
--- a/linuxthreads_db/td_ta_set_event.c
+++ b/linuxthreads_db/td_ta_set_event.c
@@ -26,11 +26,23 @@ td_ta_set_event (ta, event)
const td_thragent_t *ta;
td_thr_events_t *event;
{
+ td_thr_events_t old_event;
+ int i;
+
LOG (__FUNCTION__);
/* Write the new value into the thread data structure. */
+ if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Or the new bits in. */
+ for (i = 0; i < TD_EVENTSIZE; ++i)
+ old_event.event_bits[i] |= event->event_bits[i];
+
+ /* Write the new value into the thread data structure. */
if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
- event, sizeof (td_thrhandle_t)) != PS_OK)
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
diff --git a/linuxthreads_db/td_ta_thr_iter.c b/linuxthreads_db/td_ta_thr_iter.c
index f9b5673ebf..1fe871f4c7 100644
--- a/linuxthreads_db/td_ta_thr_iter.c
+++ b/linuxthreads_db/td_ta_thr_iter.c
@@ -26,64 +26,72 @@ td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
void *cbdata_p, td_thr_state_e state, int ti_pri,
sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
{
- struct pthread_handle_struct *handles = ta->handles;
int pthread_threads_max = ta->pthread_threads_max;
size_t sizeof_descr = ta->sizeof_descr;
+ struct pthread_handle_struct phc[pthread_threads_max];
+ int num;
int cnt;
LOG (__FUNCTION__);
+ /* Read all the descriptors. */
+ if (ps_pdread (ta->ph, ta->handles, phc,
+ sizeof (struct pthread_handle_struct) * pthread_threads_max)
+ != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Read the number of currently active threads. */
+ if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int))
+ != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
/* Now get all descriptors, one after the other. */
- for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles)
- {
- struct pthread_handle_struct phc;
-
- if (ps_pdread (ta->ph, handles, &phc,
- sizeof (struct pthread_handle_struct)) != PS_OK)
- return TD_ERR; /* XXX Other error value? */
-
- if (phc.h_descr != NULL)
- {
- struct _pthread_descr_struct pds;
- td_thrhandle_t th;
-
- if (ps_pdread (ta->ph, phc.h_descr, &pds, sizeof_descr) != PS_OK)
- return TD_ERR; /* XXX Other error value? */
-
- /* The manager thread must be handled special. The descriptor
- exists but the thread only gets created when the first
- `pthread_create' call is issued. A clear indication that
- this happened is when the p_pid field is non-zero. */
- if (cnt == 1 && pds.p_pid == 0)
- continue;
-
- /* Now test whether this thread matches the specified
- conditions. */
-
- /* Only if the priority level is as high or higher. */
- if (pds.p_priority < ti_pri)
- continue;
-
- /* Test the state.
- XXX This is incomplete. */
- if (state != TD_THR_ANY_STATE)
- continue;
-
- /* XXX For now we ignore threads which are not running anymore.
- The reason is that gdb tries to get the registers and fails.
- In future we should have a special mode of the thread library
- in which we keep the process around until the actual join
- operation happened. */
- if (pds.p_exited != 0)
- continue;
-
- /* Yep, it matches. Call the callback function. */
- th.th_ta_p = (td_thragent_t *) ta;
- th.th_unique = phc.h_descr;
- if (callback (&th, cbdata_p) != 0)
- return TD_DBERR;
- }
- }
+ for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt)
+ if (phc[cnt].h_descr != NULL)
+ {
+ struct _pthread_descr_struct pds;
+ td_thrhandle_t th;
+
+ /* First count this active thread. */
+ --num;
+
+ if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr)
+ != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* The manager thread must be handled special. The descriptor
+ exists but the thread only gets created when the first
+ `pthread_create' call is issued. A clear indication that
+ this happened is when the p_pid field is non-zero. */
+ if (cnt == 1 && pds.p_pid == 0)
+ continue;
+
+ /* Now test whether this thread matches the specified
+ conditions. */
+
+ /* Only if the priority level is as high or higher. */
+ if (pds.p_priority < ti_pri)
+ continue;
+
+ /* Test the state.
+ XXX This is incomplete. */
+ if (state != TD_THR_ANY_STATE)
+ continue;
+
+ /* XXX For now we ignore threads which are not running anymore.
+ The reason is that gdb tries to get the registers and fails.
+ In future we should have a special mode of the thread library
+ in which we keep the process around until the actual join
+ operation happened. */
+ if (pds.p_exited != 0)
+ continue;
+
+ /* Yep, it matches. Call the callback function. */
+ th.th_ta_p = (td_thragent_t *) ta;
+ th.th_unique = phc[cnt].h_descr;
+ if (callback (&th, cbdata_p) != 0)
+ return TD_DBERR;
+ }
return TD_OK;
}
diff --git a/linuxthreads_db/td_thr_clear_event.c b/linuxthreads_db/td_thr_clear_event.c
index c3c633b71d..8ef8cbbc40 100644
--- a/linuxthreads_db/td_thr_clear_event.c
+++ b/linuxthreads_db/td_thr_clear_event.c
@@ -1,4 +1,4 @@
-/* Disable specific event.
+/* Disable specific event for thread.
Copyright (C) 1999 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
@@ -18,13 +18,40 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <stddef.h>
+
#include "thread_dbP.h"
td_err_e
-td_thr_clear_event (const td_thrhandle_t *th, td_thr_events_t *event)
+td_thr_clear_event (th, event)
+ const td_thrhandle_t *th;
+ td_thr_events_t *event;
{
- /* XXX We have to figure out what has to be done. */
+ td_thr_events_t old_event;
+ int i;
+
LOG (__FUNCTION__);
- return TD_NOCAPAB;
+
+ /* Write the new value into the thread data structure. */
+ if (ps_pdread (th->th_ta_p->ph,
+ ((char *) th->th_unique
+ + offsetof (struct _pthread_descr_struct,
+ p_eventbuf.eventmask)),
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Remove the set bits in. */
+ for (i = 0; i < TD_EVENTSIZE; ++i)
+ old_event.event_bits[i] &= ~event->event_bits[i];
+
+ /* Write the new value into the thread data structure. */
+ if (ps_pdwrite (th->th_ta_p->ph,
+ ((char *) th->th_unique
+ + offsetof (struct _pthread_descr_struct,
+ p_eventbuf.eventmask)),
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ return TD_OK;
}
diff --git a/linuxthreads_db/td_thr_get_info.c b/linuxthreads_db/td_thr_get_info.c
index 606ca81f78..1e05d4c214 100644
--- a/linuxthreads_db/td_thr_get_info.c
+++ b/linuxthreads_db/td_thr_get_info.c
@@ -19,6 +19,7 @@
Boston, MA 02111-1307, USA. */
#include <stddef.h>
+#include <string.h>
#include "thread_dbP.h"
@@ -66,6 +67,8 @@ td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
infop->ti_lid = pds.p_pid;
infop->ti_ta_p = th->th_ta_p;
infop->ti_startfunc = pds.p_start_args.start_routine;
+ memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask,
+ sizeof (td_thr_events_t));
return TD_OK;
}
diff --git a/linuxthreads_db/td_thr_set_event.c b/linuxthreads_db/td_thr_set_event.c
index e6b6cbc862..583a2f8042 100644
--- a/linuxthreads_db/td_thr_set_event.c
+++ b/linuxthreads_db/td_thr_set_event.c
@@ -28,14 +28,29 @@ td_thr_set_event (th, event)
const td_thrhandle_t *th;
td_thr_events_t *event;
{
+ td_thr_events_t old_event;
+ int i;
+
LOG (__FUNCTION__);
/* Write the new value into the thread data structure. */
+ if (ps_pdread (th->th_ta_p->ph,
+ ((char *) th->th_unique
+ + offsetof (struct _pthread_descr_struct,
+ p_eventbuf.eventmask)),
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
+ return TD_ERR; /* XXX Other error value? */
+
+ /* Or the new bits in. */
+ for (i = 0; i < TD_EVENTSIZE; ++i)
+ old_event.event_bits[i] |= event->event_bits[i];
+
+ /* Write the new value into the thread data structure. */
if (ps_pdwrite (th->th_ta_p->ph,
((char *) th->th_unique
+ offsetof (struct _pthread_descr_struct,
p_eventbuf.eventmask)),
- event, sizeof (td_thrhandle_t)) != PS_OK)
+ &old_event, sizeof (td_thrhandle_t)) != PS_OK)
return TD_ERR; /* XXX Other error value? */
return TD_OK;
diff --git a/linuxthreads_db/thread_db.h b/linuxthreads_db/thread_db.h
index 8e33a06ee8..6301d7fa5f 100644
--- a/linuxthreads_db/thread_db.h
+++ b/linuxthreads_db/thread_db.h
@@ -331,10 +331,18 @@ extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki,
extern td_err_e td_ta_event_addr (const td_thragent_t *__ta,
td_event_e __event, td_notify_t *__ptr);
-/* Enable EVENT for all threads. */
+/* Enable EVENT in global mask. */
extern td_err_e td_ta_set_event (const td_thragent_t *__ta,
td_thr_events_t *__event);
+/* Disable EVENT in global mask. */
+extern td_err_e td_ta_clear_event (const td_thragent_t *__ta,
+ td_thr_events_t *__event);
+
+/* Return information about last event. */
+extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta,
+ td_event_msg_t *msg);
+
/* Set suggested concurrency level for process associated with TA. */
extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level);
diff --git a/linuxthreads_db/thread_dbP.h b/linuxthreads_db/thread_dbP.h
index 5c7fcde28a..60921834d9 100644
--- a/linuxthreads_db/thread_dbP.h
+++ b/linuxthreads_db/thread_dbP.h
@@ -41,6 +41,12 @@ struct td_thragent
/* Pointer to the `__pthread_threads_events' variable in the target. */
psaddr_t pthread_threads_eventsp;
+
+ /* Pointer to the `__pthread_last_event' variable in the target. */
+ psaddr_t pthread_last_event;
+
+ /* Pointer to the `__pthread_handles_num' variable. */
+ psaddr_t pthread_handles_num;
};