remote: get rid of all the T packets when syncing the thread list
authorPedro Alves <palves@redhat.com>
Wed, 15 Oct 2014 21:44:00 +0000 (22:44 +0100)
committerPedro Alves <palves@redhat.com>
Wed, 15 Oct 2014 21:55:14 +0000 (22:55 +0100)
This commit avoids the prune_threads call in the remote target's
target_update_thread_list's implementation, eliminating all the "thread
alive" RSP traffic (one packet per thread) whenever we fetch the
thread list.

IOW, this:

 Sending packet: $Tp2141.2150#82...Packet received: OK
 Sending packet: $Tp2141.214f#b7...Packet received: OK
 Sending packet: $Tp2141.2141#82...Packet received: OK
 ... more T packets; it's one per previously known live thread ...
 Sending packet: $qXfer:threads:read::0,fff#03...Packet received: l<threads>\n<thread id="p2141.2141" core="2"/>\n<thread id="p2141.214f" core="1"/>\n<thread id="p2141.2150" core="2"/>\n</threads>\n

Becomes:

 Sending packet: $qXfer:threads:read::0,fff#03...Packet received: l<threads>\n<thread id="p2141.2141" core="2"/>\n<thread id="p2141.214f" core="1"/>\n<thread id="p2141.2150" core="2"/>\n</threads>\n

Tested on x86_64 Fedora 20, native gdbserver:
  - tests the qXfer:threads:read method.

Tested on x86_64 Fedora 20, native gdbserver with qXfer:threads:read
force-disabled in gdbserver:
  - So that GDB falls back to the qfThreadInfo/qsThreadInfo method.

And also manually smoked tested force disabling both
qXfer:threads:read and qfThreadInfo/qsThreadInfo in gdbserver.

gdb/
2014-10-15  Pedro Alves  <palves@redhat.com>

* gdbthread.h (ALL_NON_EXITED_THREADS_SAFE): New macro.
* remote.c (remote_update_thread_list): Skip calling prune_threads
if any thread listing method is supported, and instead walk over
the set of remote threads listed, deleting those that are not
found in GDB's thread list.

gdb/ChangeLog
gdb/gdbthread.h
gdb/remote.c

index 3a6bffdcf3054bf0746e4d23d2d4b0a285147db2..abad94504a4d65f129387a52c7e8ed02fb0e4246 100644 (file)
@@ -1,3 +1,11 @@
+2014-10-15  Pedro Alves  <palves@redhat.com>
+
+       * gdbthread.h (ALL_NON_EXITED_THREADS_SAFE): New macro.
+       * remote.c (remote_update_thread_list): Skip calling prune_threads
+       if any thread listing method is supported, and instead walk over
+       the set of remote threads listed, deleting those that are not
+       found in GDB's thread list.
+
 2014-10-15  Pedro Alves  <palves@redhat.com>
 
        * ada-tasks.c (print_ada_task_info, task_command_1): Adjust.
index 1ed98a23bb8d5a1497d950249a399b1311d98b89..937bd55cd6e348811d4867edfb83bc1c77b5fd2b 100644 (file)
@@ -354,6 +354,14 @@ extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
   for (T = thread_list; T; T = T->next) \
     if ((T)->state != THREAD_EXITED)
 
+/* Like ALL_NON_EXITED_THREADS, but allows deleting the currently
+   iterated thread.  */
+#define ALL_NON_EXITED_THREADS_SAFE(T, TMP)    \
+  for ((T) = thread_list;                      \
+       (T) != NULL ? ((TMP) = (T)->next, 1): 0;        \
+       (T) = (TMP))                            \
+    if ((T)->state != THREAD_EXITED)
+
 extern int thread_count (void);
 
 /* Switch from one thread to another.  */
index cd85fd5986bb475385891990e89fe60ade50cf98..98d3f2a57f6af63f7c2aacb13e8ccc5549b04d38 100644 (file)
@@ -2762,9 +2762,7 @@ remote_update_thread_list (struct target_ops *ops)
   struct remote_state *rs = get_remote_state ();
   struct threads_listing_context context;
   struct cleanup *old_chain;
-
-  /* Delete GDB-side threads no longer found on the target.  */
-  prune_threads ();
+  int got_list = 0;
 
   context.items = NULL;
   old_chain = make_cleanup (clear_threads_listing_context, &context);
@@ -2778,8 +2776,31 @@ remote_update_thread_list (struct target_ops *ops)
     {
       int i;
       struct thread_item *item;
+      struct thread_info *tp, *tmp;
+
+      got_list = 1;
+
+      /* CONTEXT now holds the current thread list on the remote
+        target end.  Delete GDB-side threads no longer found on the
+        target.  */
+      ALL_NON_EXITED_THREADS_SAFE (tp, tmp)
+        {
+         for (i = 0;
+              VEC_iterate (thread_item_t, context.items, i, item);
+              ++i)
+           {
+             if (ptid_equal (item->ptid, tp->ptid))
+               break;
+           }
 
-      /* Now add threads we don't know about yet to our list.  */
+         if (i == VEC_length (thread_item_t, context.items))
+           {
+             /* Not found.  */
+             delete_thread (tp->ptid);
+           }
+        }
+
+      /* And now add threads we don't know about yet to our list.  */
       for (i = 0;
           VEC_iterate (thread_item_t, context.items, i, item);
           ++i)
@@ -2803,6 +2824,15 @@ remote_update_thread_list (struct target_ops *ops)
        }
     }
 
+  if (!got_list)
+    {
+      /* If no thread listing method is supported, then query whether
+        each known thread is alive, one by one, with the T packet.
+        If the target doesn't support threads at all, then this is a
+        no-op.  See remote_thread_alive.  */
+      prune_threads ();
+    }
+
   do_cleanups (old_chain);
 }