[2/2] Improve td_ta_thr_iter main thread faking logic

Message ID 1448275795-6283-3-git-send-email-gbenson@redhat.com
State New, archived
Headers

Commit Message

Gary Benson Nov. 23, 2015, 10:49 a.m. UTC
  Currently td_ta_thr_iter fakes a special descriptor for the main
thread if __stack_user == NULL.  This leaves a tiny window between
__stack_user being initialized and the main thread being added
during which td_ta_thr_iter will fail to call the callback.

This commit updates the main thread faking logic to fake the main
thread if both __stack_user and stack_used are either NULL or empty.
(It's not sufficient to key this only to __stack_user because
__reclaim_stacks can add the main thread to stack_used in which
case __stack_user will be empty but the main thread should not be
faked).
---
 nptl_db/td_ta_thr_iter.c |   32 +++++++++++++++++++++-----------
 1 files changed, 21 insertions(+), 11 deletions(-)
  

Patch

diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c
index f79a902..5d54aa4 100644
--- a/nptl_db/td_ta_thr_iter.c
+++ b/nptl_db/td_ta_thr_iter.c
@@ -23,7 +23,7 @@ 
 static td_err_e
 iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
 		     void *cbdata_p, td_thr_state_e state, int ti_pri,
-		     psaddr_t head, bool fake_empty, pid_t match_pid)
+		     psaddr_t head, int *empty_count, pid_t match_pid)
 {
   td_err_e err;
   psaddr_t next, ofs;
@@ -38,15 +38,11 @@  iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
   if (err != TD_OK)
     return err;
 
-  if (next == 0 && fake_empty)
+  if (next == 0 || next == head)
     {
-      /* __pthread_initialize_minimal has not run.  There is just the main
-	 thread to return.  We cannot rely on its thread register.  They
-	 sometimes contain garbage that would confuse us, left by the
-	 kernel at exec.  So if it looks like initialization is incomplete,
-	 we only fake a special descriptor for the initial thread.  */
-      td_thrhandle_t th = { ta, 0 };
-      return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
+      /* The list is uninitialized or empty.  */
+      (*empty_count)++;
+      return TD_OK;
     }
 
   /* Cache the offset from struct pthread to its list_t member.  */
@@ -139,6 +135,7 @@  td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
   td_thragent_t *const ta = (td_thragent_t *) ta_arg;
   td_err_e err;
   psaddr_t list = 0;
+  int empty_count = 0;
 
   LOG ("td_ta_thr_iter");
 
@@ -157,14 +154,27 @@  td_ta_thr_iter (const td_thragent_t *ta_arg, td_thr_iter_f *callback,
   err = DB_GET_SYMBOL (list, ta, __stack_user);
   if (err == TD_OK)
     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
-			       list, true, pid);
+			       list, &empty_count, pid);
 
   /* And the threads with stacks allocated by the implementation.  */
   if (err == TD_OK)
     err = DB_GET_SYMBOL (list, ta, stack_used);
   if (err == TD_OK)
     err = iterate_thread_list (ta, callback, cbdata_p, state, ti_pri,
-			       list, false, pid);
+			       list, &empty_count, pid);
+
+  if (err == TD_OK && empty_count == 2)
+    {
+      /* __pthread_initialize_minimal has not completed.  We need to
+	 call the callback for the main thread, but we cannot rely on
+	 its thread register (they sometimes contain garbage that
+	 would confuse us, left by the kernel at exec) so we fake a
+	 special descriptor for the initial thread.  */
+      td_thrhandle_t th = { ta, 0 };
+
+      if (callback (&th, cbdata_p) != 0)
+	err = TD_DBERR;
+    }
 
   return err;
 }