static ptid_t remote_current_thread (ptid_t oldptid);
 
-static void remote_find_new_threads (void);
-
 static int putpkt_binary (const char *buf, int cnt);
 
 static void check_binary_download (CORE_ADDR addr);
   return resultcount;
 }
 
+/* Fetch the next batch of threads from the remote.  Returns -1 if the
+   qL packet is not supported, 0 on error and 1 on success.  */
+
 static int
 remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
                       int *done, int *result_count, threadref *threadlist)
   pack_threadlist_request (rs->buf, startflag, result_limit, nextthread);
   putpkt (rs->buf);
   getpkt (&rs->buf, &rs->buf_size, 0);
-
   if (*rs->buf == '\0')
-    return 0;
-  else
-    *result_count =
-      parse_threadlist_response (rs->buf + 2, result_limit,
-                                &rs->echo_nextthread, threadlist, done);
+    {
+      /* Packet not supported.  */
+      return -1;
+    }
+
+  *result_count =
+    parse_threadlist_response (rs->buf + 2, result_limit,
+                              &rs->echo_nextthread, threadlist, done);
 
   if (!threadmatch (&rs->echo_nextthread, nextthread))
     {
   return result;
 }
 
-/* This is the interface between remote and threads, remotes upper
-   interface.  */
-
-/* remote_find_new_threads retrieves the thread list and for each
-   thread in the list, looks up the thread in GDB's internal list,
-   adding the thread if it does not already exist.  This involves
-   getting partial thread lists from the remote target so, polling the
-   quit_flag is required.  */
-
+/* Fetch the list of remote threads, with the qL packet, and call
+   STEPFUNCTION for each thread found.  Stops iterating and returns 1
+   if STEPFUNCTION returns true.  Stops iterating and returns 0 if the
+   STEPFUNCTION returns false.  If the packet is not supported,
+   returns -1.  */
 
 static int
 remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
          warning (_("Remote fetch threadlist -infinite loop-."));
          break;
        }
-      if (!remote_get_threadlist (startflag, &rs->nextthread,
-                                 MAXTHREADLISTRESULTS,
-                                 &done, &result_count, rs->resultthreadlist))
-       {
-         result = 0;
-         break;
-       }
+      result = remote_get_threadlist (startflag, &rs->nextthread,
+                                     MAXTHREADLISTRESULTS,
+                                     &done, &result_count,
+                                     rs->resultthreadlist);
+      if (result <= 0)
+       break;
       /* Clear for later iterations.  */
       startflag = 0;
       /* Setup to resume next batch of thread references, set nextthread.  */
                        &rs->resultthreadlist[result_count - 1]);
       i = 0;
       while (result_count--)
-       if (!(result = (*stepfunction) (&rs->resultthreadlist[i++], context)))
-         break;
+       {
+         if (!(*stepfunction) (&rs->resultthreadlist[i++], context))
+           {
+             result = 0;
+             break;
+           }
+       }
     }
   return result;
 }
 
+/* A thread found on the remote target.  */
+
+typedef struct thread_item
+{
+  /* The thread's PTID.  */
+  ptid_t ptid;
+
+  /* The thread's extra info.  May be NULL.  */
+  char *extra;
+
+  /* The core the thread was running on.  -1 if not known.  */
+  int core;
+} thread_item_t;
+DEF_VEC_O(thread_item_t);
+
+/* Context passed around to the various methods listing remote
+   threads.  As new threads are found, they're added to the ITEMS
+   vector.  */
+
+struct threads_listing_context
+{
+  /* The threads found on the remote target.  */
+  VEC (thread_item_t) *items;
+};
+
 static int
-remote_newthread_step (threadref *ref, void *context)
+remote_newthread_step (threadref *ref, void *data)
 {
+  struct threads_listing_context *context = data;
+  struct thread_item item;
   int pid = ptid_get_pid (inferior_ptid);
-  ptid_t ptid = ptid_build (pid, threadref_to_int (ref), 0);
 
-  if (!in_thread_list (ptid))
-    add_thread (ptid);
+  item.ptid = ptid_build (pid, threadref_to_int (ref), 0);
+  item.core = -1;
+  item.extra = NULL;
+
+  VEC_safe_push (thread_item_t, context->items, &item);
+
   return 1;                    /* continue iterator */
 }
 
     return oldpid;
 }
 
-/* Find new threads for info threads command.
- * Original version, using John Metzler's thread protocol.
- */
+/* List remote threads using the deprecated qL packet.  */
 
-static void
-remote_find_new_threads (void)
+static int
+remote_get_threads_with_ql (struct target_ops *ops,
+                           struct threads_listing_context *context)
 {
-  remote_threadlist_iterator (remote_newthread_step, 0,
-                             CRAZY_MAX_THREADS);
+  if (remote_threadlist_iterator (remote_newthread_step, context,
+                                 CRAZY_MAX_THREADS) >= 0)
+    return 1;
+
+  return 0;
 }
 
 #if defined(HAVE_LIBEXPAT)
 
-typedef struct thread_item
-{
-  ptid_t ptid;
-  char *extra;
-  int core;
-} thread_item_t;
-DEF_VEC_O(thread_item_t);
-
-struct threads_parsing_context
-{
-  VEC (thread_item_t) *items;
-};
-
 static void
 start_thread (struct gdb_xml_parser *parser,
              const struct gdb_xml_element *element,
              void *user_data, VEC(gdb_xml_value_s) *attributes)
 {
-  struct threads_parsing_context *data = user_data;
+  struct threads_listing_context *data = user_data;
 
   struct thread_item item;
   char *id;
            const struct gdb_xml_element *element,
            void *user_data, const char *body_text)
 {
-  struct threads_parsing_context *data = user_data;
+  struct threads_listing_context *data = user_data;
 
   if (body_text && *body_text)
     VEC_last (thread_item_t, data->items)->extra = xstrdup (body_text);
 /* Discard the contents of the constructed thread info context.  */
 
 static void
-clear_threads_parsing_context (void *p)
+clear_threads_listing_context (void *p)
 {
-  struct threads_parsing_context *context = p;
+  struct threads_listing_context *context = p;
   int i;
   struct thread_item *item;
 
 
 #endif
 
-/*
- * Find all threads for info threads command.
- * Uses new thread protocol contributed by Cisco.
- * Falls back and attempts to use the older method (above)
- * if the target doesn't respond to the new method.
- */
+/* List remote threads using qXfer:threads:read.  */
 
-static void
-remote_threads_info (struct target_ops *ops)
+static int
+remote_get_threads_with_qxfer (struct target_ops *ops,
+                              struct threads_listing_context *context)
 {
-  struct remote_state *rs = get_remote_state ();
-  char *bufp;
-  ptid_t new_thread;
-
-  if (rs->remote_desc == 0)            /* paranoia */
-    error (_("Command can only be used when connected to the remote target."));
-
 #if defined(HAVE_LIBEXPAT)
   if (packet_support (PACKET_qXfer_threads) == PACKET_ENABLE)
     {
-      char *xml = target_read_stralloc (¤t_target,
-                                        TARGET_OBJECT_THREADS, NULL);
-
+      char *xml = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
       struct cleanup *back_to = make_cleanup (xfree, xml);
 
-      if (xml && *xml)
+      if (xml != NULL && *xml != '\0')
        {
-         struct threads_parsing_context context;
-
-         context.items = NULL;
-         make_cleanup (clear_threads_parsing_context, &context);
-
-         if (gdb_xml_parse_quick (_("threads"), "threads.dtd",
-                                  threads_elements, xml, &context) == 0)
-           {
-             int i;
-             struct thread_item *item;
-
-             for (i = 0;
-                  VEC_iterate (thread_item_t, context.items, i, item);
-                  ++i)
-               {
-                 if (!ptid_equal (item->ptid, null_ptid))
-                   {
-                     struct private_thread_info *info;
-                     /* In non-stop mode, we assume new found threads
-                        are running until proven otherwise with a
-                        stop reply.  In all-stop, we can only get
-                        here if all threads are stopped.  */
-                     int running = non_stop ? 1 : 0;
-
-                     remote_notice_new_inferior (item->ptid, running);
-
-                     info = demand_private_info (item->ptid);
-                     info->core = item->core;
-                     info->extra = item->extra;
-                     item->extra = NULL;
-                   }
-               }
-           }
+         gdb_xml_parse_quick (_("threads"), "threads.dtd",
+                              threads_elements, xml, context);
        }
 
       do_cleanups (back_to);
-      return;
+      return 1;
     }
 #endif
 
+  return 0;
+}
+
+/* List remote threads using qfThreadInfo/qsThreadInfo.  */
+
+static int
+remote_get_threads_with_qthreadinfo (struct target_ops *ops,
+                                    struct threads_listing_context *context)
+{
+  struct remote_state *rs = get_remote_state ();
+
   if (rs->use_threadinfo_query)
     {
+      char *bufp;
+
       putpkt ("qfThreadInfo");
       getpkt (&rs->buf, &rs->buf_size, 0);
       bufp = rs->buf;
       if (bufp[0] != '\0')             /* q packet recognized */
        {
-         struct cleanup *old_chain;
-         char *saved_reply;
-
-         /* remote_notice_new_inferior (in the loop below) may make
-            new RSP calls, which clobber rs->buf.  Work with a
-            copy.  */
-         bufp = saved_reply = xstrdup (rs->buf);
-         old_chain = make_cleanup (free_current_contents, &saved_reply);
-
          while (*bufp++ == 'm')        /* reply contains one or more TID */
            {
              do
                {
-                 new_thread = read_ptid (bufp, &bufp);
-                 if (!ptid_equal (new_thread, null_ptid))
-                   {
-                     /* In non-stop mode, we assume new found threads
-                        are running until proven otherwise with a
-                        stop reply.  In all-stop, we can only get
-                        here if all threads are stopped.  */
-                     int running = non_stop ? 1 : 0;
+                 struct thread_item item;
 
-                     remote_notice_new_inferior (new_thread, running);
-                   }
+                 item.ptid = read_ptid (bufp, &bufp);
+                 item.core = -1;
+                 item.extra = NULL;
+
+                 VEC_safe_push (thread_item_t, context->items, &item);
                }
              while (*bufp++ == ',');   /* comma-separated list */
-             free_current_contents (&saved_reply);
              putpkt ("qsThreadInfo");
              getpkt (&rs->buf, &rs->buf_size, 0);
-             bufp = saved_reply = xstrdup (rs->buf);
+             bufp = rs->buf;
            }
-         do_cleanups (old_chain);
-         return;       /* done */
+         return 1;
+       }
+      else
+       {
+         /* Packet not recognized.  */
+         rs->use_threadinfo_query = 0;
        }
     }
 
-  /* Only qfThreadInfo is supported in non-stop mode.  */
-  if (non_stop)
-    return;
+  return 0;
+}
+
+/* Implement the to_find_new_threads function for the remote
+   targets.  */
+
+static void
+remote_threads_info (struct target_ops *ops)
+{
+  struct remote_state *rs = get_remote_state ();
+  struct threads_listing_context context;
+  struct cleanup *old_chain;
+
+  context.items = NULL;
+  old_chain = make_cleanup (clear_threads_listing_context, &context);
+
+  /* We have a few different mechanisms to fetch the thread list.  Try
+     them all, starting with the most preferred one first, falling
+     back to older methods.  */
+  if (remote_get_threads_with_qxfer (ops, &context)
+      || remote_get_threads_with_qthreadinfo (ops, &context)
+      || remote_get_threads_with_ql (ops, &context))
+    {
+      int i;
+      struct thread_item *item;
 
-  /* Else fall back to old method based on jmetzler protocol.  */
-  rs->use_threadinfo_query = 0;
-  remote_find_new_threads ();
-  return;
+      /* Add threads we don't know about yet to our list.  */
+      for (i = 0;
+          VEC_iterate (thread_item_t, context.items, i, item);
+          ++i)
+       {
+         if (!ptid_equal (item->ptid, null_ptid))
+           {
+             struct private_thread_info *info;
+             /* In non-stop mode, we assume new found threads are
+                running until proven otherwise with a stop reply.  In
+                all-stop, we can only get here if all threads are
+                stopped.  */
+             int running = non_stop ? 1 : 0;
+
+             remote_notice_new_inferior (item->ptid, running);
+
+             info = demand_private_info (item->ptid);
+             info->core = item->core;
+             info->extra = item->extra;
+             item->extra = NULL;
+           }
+       }
+    }
+
+  do_cleanups (old_chain);
 }
 
 /*