public inbox for archer-commits@sourceware.org
help / color / mirror / Atom feed
From: scox@sourceware.org
To: archer-commits@sourceware.org
Subject: [SCM]  scox/globalstate: Improve non-stop multi client handling.
Date: Mon, 04 Jan 2016 15:32:00 -0000	[thread overview]
Message-ID: <20160104153210.63421.qmail@sourceware.org> (raw)

The branch, scox/globalstate has been updated
       via  86f94295634f71220c6e6c4ac987406be3014e59 (commit)
      from  0bee029c99922ca26020016079c299fe2b01df59 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email.

- Log -----------------------------------------------------------------
commit 86f94295634f71220c6e6c4ac987406be3014e59
Author: Stan Cox <scox@redhat.com>
Date:   Sun Jan 3 21:37:56 2016 -0500

    Improve non-stop multi client handling.
    
    gdbserver/ChangeLog:
    
    	* server.c (add_client_by_pid):  Add non_stop, multi_process_, and run_once_.
    	(have_multiple_clients): Add vCont;t and vStopped and vAttach.
    	(resolve_waiter): Add vContc, non_stop, and vContt
    	(setup_multiplexing): Add vContt and pending_stop for non_stop.
    	(notify_clients): New to send stop notification to multiple clients.
    	(do_multiplexing):  Call notify_clients.  Make vContt aware.
    	(handle_v_attach):  Make non_stop aware.
    
    	* server.h (last_status_exited, vContt, vStopped, vAttach)
    	(exit_types):  New.
    
    	* mem-break.c (has_client_breakpoint_at): Simplify.  Improve
    	debug_threads output.
    
    testsuite/ChangeLog:
    
    	* gdb.server/multi-client.exp: Add non-stop test.

-----------------------------------------------------------------------

Summary of changes:
 gdb/gdbserver/ChangeLog                   |   16 ++
 gdb/gdbserver/event-loop.c                |    2 +-
 gdb/gdbserver/mem-break.c                 |   30 ++--
 gdb/gdbserver/server.c                    |  292 ++++++++++++++++++++---------
 gdb/gdbserver/server.h                    |    9 +-
 gdb/testsuite/ChangeLog                   |    4 +
 gdb/testsuite/gdb.server/multi-client.exp |  141 ++++++++-------
 7 files changed, 321 insertions(+), 173 deletions(-)

First 500 lines of diff:
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 3ac724f..d9c99e4 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,19 @@
+2016-01-03  Stan Cox  <scox@redhat.com>
+
+	* server.c (add_client_by_pid):  Add non_stop, multi_process_, and run_once_.
+	(have_multiple_clients): Add vCont;t and vStopped and vAttach.
+	(resolve_waiter): Add vContc, non_stop, and vContt
+	(setup_multiplexing): Add vContt and pending_stop for non_stop.
+	(notify_clients): New to send stop notification to multiple clients.
+	(do_multiplexing):  Call notify_clients.  Make vContt aware.
+	(handle_v_attach):  Make non_stop aware.
+
+	* server.h (last_status_exited, vContt, vStopped, vAttach)
+	(exit_types):  New.
+
+	* mem-break.c (has_client_breakpoint_at): Simplify.  Improve
+	debug_threads output.
+
 2015-11-04  Stan Cox  <scox@redhat.com>
 
 	* server.h (client_state):  Remove executable and all its references.
diff --git a/gdb/gdbserver/event-loop.c b/gdb/gdbserver/event-loop.c
index 1679464..00feb4f 100644
--- a/gdb/gdbserver/event-loop.c
+++ b/gdb/gdbserver/event-loop.c
@@ -428,7 +428,7 @@ handle_file_event (gdb_fildes_t event_file_desc)
 	  if (mask != 0)
 	    {
 	      /* Don't change client states if we have multiple clients */
-	      if (have_multiple_clients (file_ptr->fd) || ptid_equal (general_thread, null_ptid))
+	      if (have_multiple_clients (file_ptr->fd))
 		set_client_state (file_ptr->fd);
 	      if ((*file_ptr->proc) (file_ptr->error,
 				     file_ptr->client_data) < 0)
diff --git a/gdb/gdbserver/mem-break.c b/gdb/gdbserver/mem-break.c
index 138e8e0..898d370 100644
--- a/gdb/gdbserver/mem-break.c
+++ b/gdb/gdbserver/mem-break.c
@@ -301,23 +301,25 @@ has_client_breakpoint_at (CORE_ADDR addr)
   client_state *cs = get_client_state ();
 
   struct client_breakpoint *cb;
-  if (debug_threads)
-    debug_printf ("%s:%d fd=%d addr=%#lx\n", __FUNCTION__, __LINE__, cs->file_desc, (long unsigned)addr);
+
   for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
-    if (debug_threads)
-      debug_printf ("%s:%d %d breakpoint at %#lx\n", __FUNCTION__, __LINE__, cs->file_desc, (long unsigned)cb->addr);
+    {
+      // TODO improve this; pc might be one insn ahead of break. 
+      if (addr >= cb->addr && addr <= cb->addr + 8)
+	{
+	  if (debug_threads)
+	    debug_printf ("%s:%d fd=%d return true at %#lx\n", 
+			  __FUNCTION__, __LINE__, cs->file_desc, (long unsigned)cb->addr);
+	  return 1;
+	}
+    }
 
-  //  for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
+  if (debug_threads)
     {
-      //      if (addr >= bp->pc && addr <= bp->pc + 8 && cs->ss->last_status.kind == TARGET_WAITKIND_STOPPED
-      //	  && cs->ss->last_status.value.sig == GDB_SIGNAL_TRAP)
-	  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
-	    // TODO improve this; pc might be one insn ahead of break. 
-	    {
-	      debug_printf ("%s:%d addr=%#lx pb->pc %#lx in range? %d\n", __FUNCTION__, __LINE__, (long unsigned) addr, (long unsigned)cb->addr, addr >= cb->addr && addr <= cb->addr + 8);
-	      if (addr >= cb->addr && addr <= cb->addr + 8)
-		return 1;
-	    }
+      debug_printf ("%s:%d fd=%d addr=%#lx breakpoints at:\n", __FUNCTION__, __LINE__, cs->file_desc, (long unsigned)addr);
+      for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
+	debug_printf (" %#lx", (long unsigned)cb->addr);
+      debug_printf ("\n");
     }
   return 0;
 }
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index cb552ec..64bf851 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -85,9 +85,9 @@ static struct client_states  client_states;
 
 static void handle_status (char *);
 
-enum pending_types  {none_pending=0, pending_waitee=1, pending_cont_waiter=2,pending_step_waiter=3};
-char *pending_types_str[] = {"not waiting","waitee","waiter","step waiter"};
-char *packet_types_str[] = {"other", "vContc", "vConts","vRun"};
+enum pending_types  {none_pending, pending_waitee, pending_cont_waiter,pending_step_waiter,pending_stop};
+char *pending_types_str[] = {"not waiting","waitee","waiter","step waiter","stop"};
+char *packet_types_str[] = {"other", "vContc", "vConts","vContt","vStopped","vRun", "vAttach"};
 
 
 /* Return the current client state */
@@ -148,6 +148,8 @@ set_client_state (gdb_fildes_t fd)
   *client_states.current_cs->ss = *csidx->ss;
   cs = client_states.current_cs;
   cs->packet_type = other_packet;
+  cs->last_packet_type = other_packet;
+  cs->pending = none_pending;
   cs->client_breakpoints = NULL;
   in_buffer = NULL;
   wrapper_argv = NULL;
@@ -259,7 +261,7 @@ static void free_client_state (client_state *cs)
 /* Dump the client state list for debugging purposes */
 
 void
-dump_client_state (const char *comment)
+dump_client_state (const char *function, const char *comment)
 {
   client_state *save_cs = get_client_state();
   client_state *cs;
@@ -267,10 +269,12 @@ dump_client_state (const char *comment)
   if (! debug_threads)
     return;
   
-  debug_printf ("***Begin Dumping client state from %s\n", comment);
+  debug_printf ("***Begin Dumping client state from %s %s\n", function, comment);
   for (cs = client_states.first; cs != NULL; cs = cs->next)
     {
       client_states.current_cs = cs;
+      if (cs->file_desc == -1)
+	continue;
       debug_printf ("%d %#lx(%d)/%#lx/%#lx #=%d %s %s %s\n",
 		    cs->file_desc, 
 		    (long unsigned)general_thread.pid, 
@@ -282,7 +286,7 @@ dump_client_state (const char *comment)
 		    packet_types_str[cs->last_packet_type], 
 		    pending_types_str[cs->pending]);
     }
-  debug_printf ("***End Dumping client state from %s\n", comment);
+  debug_printf ("***End Dumping client state\n");
   client_states.current_cs = save_cs;
 }
 
@@ -294,15 +298,16 @@ add_client_by_pid (int pid)
 {
   client_state *cs = get_client_state();
   client_state *matched_cs;
-
   for (matched_cs = client_states.first; matched_cs != NULL; matched_cs = matched_cs->next)
     {
       if (cs != matched_cs && matched_cs->ss->general_thread_.pid == pid)
 	{
-	  XDELETE (cs->ss);
 	  /* reuse the matched server state */
 	  cs->ss = matched_cs->ss;
 	  cs->ss->attach_count_ += 1;
+	  cs->non_stop_ = matched_cs->non_stop_;
+	  cs->multi_process_ = matched_cs->multi_process_;
+	  cs->run_once_ = matched_cs->run_once_;
 	  return cs;
 	}
     }
@@ -331,7 +336,7 @@ int
 have_multiple_clients (gdb_fildes_t fd)
 {
   client_state *cs;
-  dump_client_state(__FUNCTION__);
+  dump_client_state(__FUNCTION__, "");
 
   for (cs = client_states.first; cs != NULL; cs = cs->next)
     if (cs->file_desc == fd)
@@ -387,23 +392,33 @@ get_packet_type (client_state *cs)
   else
     return other_packet;
   /* We have already categorized the packet type */
+
   if (cs->pending == pending_cont_waiter || cs->pending == pending_step_waiter)
     return other_packet;
 
   switch (own_packet)
-  {
+    {
     case 'v':
       if ((strncmp (in_buffer, "vCont;c", 7) == 0))
 	return vContc;
-      else if ((strncmp (in_buffer, "vCont;r", 7) == 0) || (strncmp (in_buffer, "vCont;s", 7) == 0))
+      else if ((strncmp (in_buffer, "vCont;r", 7) == 0) 
+	       || (strncmp (in_buffer, "vCont;s", 7) == 0))
 	return vConts;
+      else if ((strncmp (in_buffer, "vCont;t", 7) == 0))
+	return vContt;
+      else if ((strncmp (in_buffer, "vStopped", 8) == 0))
+	return vStopped;
       else if (strncmp (in_buffer, "vRun", 4) == 0)
 	return vRun;
-      break;
-  };
-  return other_packet;
+      else if (strncmp (in_buffer, "vAttach", 4) == 0)
+	return vAttach;
+    default:
+      return other_packet;
+    };
 }
 
+static int queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg);
+
 /* Belatedly reply to last CS previously received and waited on packet  */
 
 void
@@ -418,18 +433,30 @@ resolve_waiter (client_state *cs)
   {
     case vContc:
       {
-	if (last_status.kind != TARGET_WAITKIND_EXITED)
+	if (non_stop)
 	  {
-	    /* reply to vContc with a status */
-	    strcpy (own_buffer, "?");
-	    handle_status (own_buffer);
-	    putpkt (own_buffer);
+	    if (last_status.kind != TARGET_WAITKIND_EXITED
+		&& last_status.kind != TARGET_WAITKIND_STOPPED)
+	      {
+		/* Create a stop notification */
+		struct vstop_notif *new_notif = XNEW (struct vstop_notif);
+		char *notif_buf;
+		notif_buf = alloca (PBUFSIZ + 1);
+		write_ok (notif_buf);
+		putpkt (notif_buf);
+
+		new_notif->ptid = general_thread;
+		new_notif->status = last_status;
+		new_notif->status.kind = TARGET_WAITKIND_STOPPED;
+		notif_push (&notif_stop,
+				   (struct notif_event *) new_notif);
+		/* Explicit write of notification and remove from queue */
+		discard_queued_stop_replies (cs->ss->general_thread_);
+
+		notif_write_event (&notif_stop, notif_buf);
+	      }
 	  }
-	break;
-      }
-    case vConts:
-      {
-	if (last_status.kind != TARGET_WAITKIND_EXITED)
+	else if (last_status.kind != TARGET_WAITKIND_EXITED)
 	  {
 	    /* reply to vContc with a status */
 	    strcpy (own_buffer, "?");
@@ -438,27 +465,60 @@ resolve_waiter (client_state *cs)
 	  }
 	break;
       }
-    case vRun:
-      {
-	/* reply to vRun with an OK */
-	strcpy (own_buffer, "OK");
-	putpkt (own_buffer);
-	break;
-      }
-    default:
+  case vConts:
+    {
+      if (last_status.kind != TARGET_WAITKIND_EXITED)
+	{
+	  /* reply to vContc with a status */
+	  strcpy (own_buffer, "?");
+	  handle_status (own_buffer);
+	  putpkt (own_buffer);
+	}
       break;
+    }
+  case vContt:
+    {
+      if (last_status.kind != TARGET_WAITKIND_EXITED
+	  && last_status.kind != TARGET_WAITKIND_STOPPED)
+	{
+	  char *notif_buf, *out_buf;
+	  notif_buf = alloca (PBUFSIZ + 1);
+	  write_ok (notif_buf);
+	  putpkt (notif_buf);
+
+	  find_inferior (&all_threads, queue_stop_reply_callback, NULL);
+	  notif_write_event (&notif_stop, notif_buf);
+	  out_buf = alloca (strlen (notif_buf) + 8);
+	  // TODO Use Defined notif constant
+	  strcpy (out_buf, "Stop:");
+	  strcat (out_buf, notif_buf);
+	  putpkt_notif (out_buf);
+	  if (debug_threads)
+	    debug_printf ("%s:%d %s\n", __FUNCTION__, __LINE__, out_buf);
+	}
+      break;
+    }
+  case vRun:
+    {
+      /* reply to vRun with an OK */
+      strcpy (own_buffer, "OK");
+      putpkt (own_buffer);
+      break;
+    }
+  default:
+    break;
   };
 }
 
 
 /* Determine the state of client CS with respect to other clients connected to the same server process */
 
-int
+static int
 setup_multiplexing (client_state *cs, char *ch)
 {
   client_state *csidx = NULL;
 
-  dump_client_state (__FUNCTION__);
+  dump_client_state (__FUNCTION__, "");
 
   cs->attached_to_client = 1;
 
@@ -467,41 +527,27 @@ setup_multiplexing (client_state *cs, char *ch)
       /* another client is attached to the cs process */
       if (csidx->file_desc != -1 && csidx != cs && cs->ss == csidx->ss)
 	{
-	  if (debug_threads)
-	    debug_printf ("%s:%d before csidx fd=%d %s %s cs fd=%d %s %s\n", __FUNCTION__, __LINE__, csidx->file_desc, pending_types_str[csidx->pending], packet_types_str[csidx->packet_type], cs->file_desc, pending_types_str[cs->pending], packet_types_str[cs->packet_type]);
     	  /* found a client that has nothing pending */
 	  if (!csidx->pending)
 	    {
-	      int already_have_waitee = 0;
-	      client_state *csi;
-	      /* Does the client group have a waitee? */
-	      for (csi = client_states.first->next; csi != NULL; csi = csi->next)
-		{
-		  if (csi->ss == cs->ss && csi->pending == pending_waitee
-		      && csi->file_desc != cs->file_desc && csi->file_desc != csidx->file_desc)
-		    already_have_waitee = 1;
-		}
-
 	      /* The cs vContc will wait; found csidx will proceed */
 	      if (cs->packet_type == vContc)
 		{
 		  if (cs->last_packet_type != vRun)
 		    {
 		      cs->pending = pending_cont_waiter;
- 		      if (1 || already_have_waitee)
 		      csidx->pending = pending_waitee;
 		    }
 		}
+	      /* TODO else if (cs->packet_type == vContt) */
 	      else if (cs->packet_type == vConts)
 		{
-		  if (cs->last_packet_type != vRun)
+		  if (csidx->last_packet_type != vContt)
 		    {
 		      cs->pending = pending_step_waiter;
 		      csidx->pending = pending_waitee;
 		    }
 		}
-	      if (debug_threads)
-		debug_printf ("%s:%d after csidx fd=%d %s %s cs fd=%d %s %s\n", __FUNCTION__, __LINE__, csidx->file_desc, pending_types_str[csidx->pending], packet_types_str[csidx->packet_type], cs->file_desc, pending_types_str[cs->pending], packet_types_str[cs->packet_type]);
 	    }
 	  /* Current client is continuing and found another waiter client */
 	  else if (csidx->pending == pending_cont_waiter
@@ -518,67 +564,118 @@ setup_multiplexing (client_state *cs, char *ch)
 		    waitee_count = 1;
 		}
 
-	      debug_printf ("%s:%d waitee_count=%d cs pending %s\n", __FUNCTION__, __LINE__, waitee_count, pending_types_str[cs->pending]);
-
 	      /* Don't want to deadlock on everyone waiting */
 	      if (cs->pending == pending_waitee && waitee_count > 0)
 		cs->pending = pending_cont_waiter;
 	    }
 	}
     }
-  dump_client_state (__FUNCTION__);
 
   /* Current client is continuing and waiting so just return.
      The packet will be replied to later in do_multiplexing */
   if (cs->pending == pending_cont_waiter 
-      || cs->pending == pending_step_waiter)
+      || cs->pending == pending_step_waiter
+      || cs->pending == pending_stop)
     {
-      if (cs->last_packet_type != vRun)
-	return 0;
+      if (cs->last_packet_type != vRun 
+	  && cs->last_packet_type != vStopped
+	  && cs->ss->last_status_exited != have_exit)
+	{
+	  dump_client_state (__FUNCTION__, "return 0");
+	  return 0;		/* Reply to packet later */
+	}
     }
-  return 1;
+  dump_client_state (__FUNCTION__, "return 1");
+  return 1;			/* Reply to packet now */
+}
+
+
+static void
+notify_clients (client_state *waitee_cs)
+{
+  client_state *csidx = NULL;
+
+  if (! (waitee_cs->pending == pending_waitee
+	 && waitee_cs->last_packet_type == vStopped
+	 && waitee_cs->ss->last_status_exited == have_exit))
+    return;
+
+  for (csidx = client_states.first; csidx != NULL; csidx = csidx->next)
+    {
+      /* Insure another client is attached to the cs process */
+      if (csidx->file_desc == -1 ||csidx->file_desc == waitee_cs->file_desc
+	  || waitee_cs->ss != csidx->ss)
+	continue;
+      {
+	char *out_buf = alloca (64);
+
+	csidx->ss->last_status_exited = sent_exit;
+	set_client_state (csidx->file_desc);
+	csidx->pending = none_pending;
+	strcpy (out_buf, "OK");
+	putpkt (out_buf);
+	// TODO Use a better method to create this: Stop:W0;process:29e3
+	sprintf (out_buf, "Stop:W0;process:%x", (unsigned)ptid_get_pid (general_thread));
+	putpkt_notif (out_buf);
+	if (debug_threads)
+	  debug_printf ("%s:%d %s\n", __FUNCTION__, __LINE__, out_buf);
+      }
+    }
+  set_client_state (waitee_cs->file_desc);
+  return;
 }
 
 
 /* Resolve the state of client WAITEE_CS with respect to other clients connected to the same server process */
 
-int
+static int
 do_multiplexing (client_state *waitee_cs, char ch)
 {
   client_state *csidx = NULL;
   int make_waitee_a_waiter = 0;
 
+  if (waitee_cs->last_packet_type == vAttach && waitee_cs->packet_type == vContt)
+    {
+      resolve_waiter (waitee_cs);
+      dump_client_state (__FUNCTION__, "resolved vContt");
+      return 0;
+    }
+
   if (waitee_cs->packet_type != other_packet)
     waitee_cs->last_packet_type = waitee_cs->packet_type;
 
-  dump_client_state (__FUNCTION__);
+  dump_client_state (__FUNCTION__, "");
+
+  if (waitee_cs->ss->last_status_exited == have_exit)
+    notify_clients (waitee_cs);
 
   /* Current client is a waitee that is continuing */
-  if (! ((waitee_cs->packet_type == vContc
-	  || waitee_cs->packet_type == vConts)
-	 && waitee_cs->pending == pending_waitee))
+  if (! (waitee_cs->pending == pending_waitee
+	 && (waitee_cs->packet_type == vContc
+	     || waitee_cs->packet_type == vContt)))
     {
-      if (debug_threads)
-	debug_printf ("%s:%d returning for waitee %d\n", __FUNCTION__, __LINE__, waitee_cs->file_desc);
+      dump_client_state (__FUNCTION__, "no action taken");
       return 1;
     }
-  
+
   for (csidx = client_states.first; csidx != NULL; csidx = csidx->next)
     {
       client_state *waiter_cs;
       /* Insure another client is attached to the cs process */
       if (csidx->file_desc == -1 || waitee_cs->ss != csidx->ss)
 	continue;
-      if (debug_threads)
-	debug_printf ("%s:%d before csidx fd=%d %s %s cs fd=%d %s %s\n", __FUNCTION__, __LINE__, csidx->file_desc, pending_types_str[csidx->pending], packet_types_str[csidx->packet_type], waitee_cs->file_desc, pending_types_str[waitee_cs->pending], packet_types_str[waitee_cs->packet_type]);
       if (csidx->pending == pending_cont_waiter)
 	{
 	  /* Found a vContc packet that is waiting */
 	  if (csidx->packet_type == vContc
-	      || csidx->last_packet_type == vContc)
+	      || csidx->last_packet_type == vContc
+	      || csidx->last_packet_type == vContt) // TODO
 	    {
 	      char save_ch = ch;
 	      int waitee_has_bp, waiter_has_bp;
+
+	      prepare_to_access_memory ();
+
 	      if (waitee_cs->ss->last_status_.kind == TARGET_WAITKIND_EXITED)
 		{
 		  waiter_cs = set_client_state (csidx->file_desc);
@@ -588,12 +685,15 @@ do_multiplexing (client_state *waitee_cs, char ch)


hooks/post-receive
--
Repository for Project Archer.


                 reply	other threads:[~2016-01-04 15:32 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160104153210.63421.qmail@sourceware.org \
    --to=scox@sourceware.org \
    --cc=archer-commits@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).