public inbox for archer-commits@sourceware.org
help / color / mirror / Atom feed
* [SCM]  scox/globalstate: Handle more than two clients more gracefully.
@ 2015-10-07 18:24 scox
  0 siblings, 0 replies; only message in thread
From: scox @ 2015-10-07 18:24 UTC (permalink / raw)
  To: archer-commits

The branch, scox/globalstate has been updated
       via  f5936a9aa6a56493123550de032fcd93f26e57c2 (commit)
      from  589dd9c8abac87fa8306733f9e6b56af97e739fb (commit)

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

- Log -----------------------------------------------------------------
commit f5936a9aa6a56493123550de032fcd93f26e57c2
Author: Stan Cox <scox@redhat.com>
Date:   Wed Oct 7 14:23:18 2015 -0400

    Handle more than two clients more gracefully.
    
    	* server.c (setup_multiplexing): Insure we always have a waitee.
    	(do_multiplexing): Don't wait if break isn't reached.

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

Summary of changes:
 gdb/gdbserver/ChangeLog                   |    5 +
 gdb/gdbserver/event-loop.c                |    2 +-
 gdb/gdbserver/server.c                    |  250 +++++++++++++++++++---------
 gdb/testsuite/gdb.server/multi-client.exp |   29 +++-
 4 files changed, 198 insertions(+), 88 deletions(-)

First 500 lines of diff:
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 6c80e10..c8e33f7 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-06  Stan Cox  <scox@redhat.com>
+
+	* server.c (setup_multiplexing): Insure we always have a waitee.
+	(do_multiplexing): Don't wait if break isn't reached.
+
 2015-09-24  Stan Cox  <scox@redhat.com>
 
 	* server.c (get_client_state, set_client_state)
diff --git a/gdb/gdbserver/event-loop.c b/gdb/gdbserver/event-loop.c
index 3724cd7..92287c2 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 ())
+	      if (have_multiple_clients () || get_client_state()->executable == 0)
 		set_client_state (file_ptr->fd);
 	      if ((*file_ptr->proc) (file_ptr->error,
 				     file_ptr->client_data) < 0)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 07828c2..5e04a1e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -85,6 +85,10 @@ 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"};
+
 
 /* Return the current client state */
 
@@ -95,7 +99,7 @@ get_client_state (void)
 }
 
 
-/* Add a new client state for fd or return if found */
+/* Add a new client state for FD or return if found */
 
 client_state *
 set_client_state (gdb_fildes_t fd)
@@ -175,15 +179,45 @@ set_client_state (gdb_fildes_t fd)
   return client_states.current_cs;
 }
 
+/* Add breakpoint ADDR to the per client breakpoint list */
+
+void
+add_client_breakpoint (CORE_ADDR addr)
+{
+  struct client_breakpoint *cb;
+  struct client_breakpoint *newcb;
+  client_state *cs = get_client_state();
+
+  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
+    if (addr == cb->addr)
+      return;
+    else if (cb->next == NULL)
+      break;
+  newcb = XCNEW (struct client_breakpoint);
+  if (cb != NULL)
+    cb->next = newcb;
+  else
+    cs->client_breakpoints = newcb;
+  newcb->addr = addr;
+  newcb->next = NULL;
+
+  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
+    if (debug_threads)
+      debug_printf ("%s:%d %d %#lx  breakpoint at %#lx\n", __FUNCTION__, __LINE__, get_client_state()->file_desc, (long unsigned)addr, (long unsigned)cb->addr);
+}
+
+
+/* Remove ADDR from the per client breakpoint list */
 
 void
 delete_client_breakpoint (CORE_ADDR addr)
 {
+  /* TODO gdb_remove_breakpoint removes breakpoints when we expect them
+     so lifetimes of list items needs improvement */
   struct client_breakpoint *cb;
   struct client_breakpoint *previous_cb = NULL;
   client_state *cs = get_client_state();
 
-  //  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
   cb = cs->client_breakpoints;
   while (cb != NULL)
     {
@@ -210,7 +244,7 @@ delete_client_breakpoint (CORE_ADDR addr)
 }
 
 
-/* Free client state cs, taking into account the corresponding server state */
+/* Free client state CS; considering the corresponding server state */
 
 static void free_client_state (client_state *cs)
 {
@@ -235,27 +269,35 @@ static void free_client_state (client_state *cs)
 }
 
 
+/* Dump the client state list for debugging purposes */
+
 void
-dump_client_state ()
+dump_client_state (const char *comment)
 {
   client_state *save_cs = get_client_state();
   client_state *cs;
+
+  if (! debug_threads)
+    return;
+  
+  debug_printf ("Dumping client state from %s\n", comment);
+  
   for (cs = client_states.first; cs != NULL; cs = cs->next)
-      if (debug_threads)
-	{
-	  client_states.current_cs = cs;
-	  debug_printf ("%s:%d %s %d cont_thr %#lx gen thr %#lx attached? %d\n", __FUNCTION__, __LINE__,
-			cs->executable, cs->file_desc, (long unsigned)cont_thread.pid,
-			(long unsigned)general_thread.pid, cs->ss->attach_count);
-	  debug_printf ("%s:%d %d all procs %#lx all thrs %#lx curr thr %#lx\n", __FUNCTION__, __LINE__,
-			(int)last_ptid.pid, (unsigned long)all_processes.head,
-			(unsigned long)all_threads.head, (unsigned long)current_thread);
+    {
+      client_states.current_cs = cs;
+      debug_printf ("%s %d cont_thr %#lx gen thr %#lx attached? %d\n",
+		    cs->executable, cs->file_desc, (long unsigned)cont_thread.pid,
+		    (long unsigned)general_thread.pid, cs->ss->attach_count);
+      debug_printf ("%d all procs %#lx all thrs %#lx curr thr %#lx %s/%s/%s\n",
+		    (int)last_ptid.pid, (unsigned long)all_processes.head,
+		    (unsigned long)all_threads.head, (unsigned long)current_thread,
+		    packet_types_str[cs->packet_type], packet_types_str[cs->last_packet_type], pending_types_str[cs->pending]);
     }
   client_states.current_cs = save_cs;
 }
 
 
-/* Add another client to the 1 server -> N client list. */
+/* Add another client for PID to the 1 server -> N client list. */
 
 client_state *
 add_client_by_pid (int pid)
@@ -271,7 +313,8 @@ add_client_by_pid (int pid)
 	  xfree (cs->executable);
 	  cs->executable = matched_cs->executable;
 	  XDELETE (cs->ss);
-	  cs->ss = matched_cs->ss;		/* reuse the matched server state */
+	  /* reuse the matched server state */
+	  cs->ss = matched_cs->ss;
 	  cs->ss->attach_count += 1;
 	  return cs;
 	}
@@ -280,6 +323,8 @@ add_client_by_pid (int pid)
 }
 
 
+/* Add another client for EXECUTABLE to the 1 server -> N client list. */
+
 client_state *
 add_client_by_exe (char *executable)
 {
@@ -287,7 +332,7 @@ add_client_by_exe (char *executable)
   char *new_executable;
   client_state *cs = get_client_state ();
 
-  dump_client_state();
+  dump_client_state(__FUNCTION__);
 
   for (csi = client_states.first; csi != NULL; csi = csi->next)
     {
@@ -302,7 +347,7 @@ add_client_by_exe (char *executable)
 }
 
 
-/* Return the first real client state */
+/* Return the first active client state */
 
 gdb_fildes_t
 get_first_client_fd ()
@@ -319,7 +364,7 @@ get_first_client_fd ()
 }
 
 
-/* Is there more than one client? */
+/* Is there more than one active client? */
 
 int
 have_multiple_clients ()
@@ -335,7 +380,7 @@ have_multiple_clients ()
 }
 
 
-/*  Remove the client state corresponding to fd */
+/* Remove the client state corresponding to fd */
 
 void
 delete_client_state (gdb_fildes_t fd)
@@ -370,35 +415,7 @@ delete_client_state (gdb_fildes_t fd)
 }
 
 
-void
-add_client_breakpoint (CORE_ADDR addr)
-{
-  struct client_breakpoint *cb;
-  struct client_breakpoint *newcb;
-  client_state *cs = get_client_state();
-
-  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
-    if (addr == cb->addr)
-      return;
-    else if (cb->next == NULL)
-      break;
-  newcb = XCNEW (struct client_breakpoint);
-  if (cb != NULL)
-    cb->next = newcb;
-  else
-    cs->client_breakpoints = newcb;
-  newcb->addr = addr;
-  newcb->next = NULL;
-
-  for (cb = cs->client_breakpoints; cb != NULL; cb = cb->next)
-    if (debug_threads)
-      debug_printf ("%s:%d %d %#lx  breakpoint at %#lx\n", __FUNCTION__, __LINE__, get_client_state()->file_desc, (long unsigned)addr, (long unsigned)cb->addr);
-}
-
-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"};
-
+/* Return the packet type for last CS packets */
 
 packet_types
 get_packet_type (client_state *cs)
@@ -427,17 +444,23 @@ get_packet_type (client_state *cs)
   return other_packet;
 }
 
-/* output a packet that will cause the packet to be ignored.  */
+/* Belatedly reply to last CS previously received and waited on packet  */
 
 void
 resolve_waiter (client_state *cs)
 {
-  switch (cs->packet_type)
+  enum packet_types this_packet_type = (cs->packet_type) ? cs->packet_type : cs->last_packet_type;
+
+  if (debug_threads)
+    debug_printf ("%s:%d fd=%d %s\n", __FUNCTION__, __LINE__, cs->file_desc, packet_types_str[this_packet_type]);
+
+  switch (this_packet_type)
   {
     case vContc:
       {
 	if (last_status.kind != TARGET_WAITKIND_EXITED)
 	  {
+	    /* reply to vContc with a status */
 	    strcpy (own_buffer, "?");
 	    handle_status (own_buffer);
 	    putpkt (own_buffer);
@@ -448,6 +471,7 @@ resolve_waiter (client_state *cs)
       {
 	if (last_status.kind != TARGET_WAITKIND_EXITED)
 	  {
+	    /* reply to vContc with a status */
 	    strcpy (own_buffer, "?");
 	    handle_status (own_buffer);
 	    putpkt (own_buffer);
@@ -456,37 +480,55 @@ resolve_waiter (client_state *cs)
       }
     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
 setup_multiplexing (client_state *cs, char *ch)
-{ /* Handle pending type */
+{
   client_state *csidx = NULL;
 
+  dump_client_state (__FUNCTION__);
+
   for (csidx = client_states.first; csidx != NULL; csidx = csidx->next)
     {
       /* 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 csidx %s %s cs %s %s\n", __FUNCTION__, __LINE__, pending_types_str[csidx->pending], packet_types_str[csidx->packet_type], pending_types_str[cs->pending], packet_types_str[cs->packet_type]);
-	  /* find this client's pending type */
+	    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;
 		    }
-
 		}
 	      else if (cs->packet_type == vConts)
 		{
@@ -497,14 +539,35 @@ setup_multiplexing (client_state *cs, char *ch)
 		    }
 		}
 	      if (debug_threads)
-		debug_printf ("%s:%d %d=%s %d=%s\n", __FUNCTION__, __LINE__,
-			      csidx->file_desc, pending_types_str[csidx->pending],
-			      cs->file_desc, pending_types_str[cs->pending]);
+		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
+		   && cs->packet_type == vContc)
+	    {
+	      client_state *csi;
+	      int waitee_count = 0;
+	      
+	      /* 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)
+		    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;
 	    }
 	}
     }
-  if (debug_threads)
-    debug_printf ("%s:%d pending check %d %s\n", __FUNCTION__, __LINE__,cs->file_desc,pending_types_str[cs->pending]);
+  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)
     {
@@ -515,26 +578,42 @@ setup_multiplexing (client_state *cs, char *ch)
 }
 
 
+/* Resolve the state of client WAITEE_CS with respect to other clients connected to the same server process */
+
 int
 do_multiplexing (client_state *waitee_cs, char ch)
 {
   client_state *csidx = NULL;
+  int make_waitee_a_waiter = 0;
 
   if (waitee_cs->packet_type != other_packet)
     waitee_cs->last_packet_type = waitee_cs->packet_type;
 
+  dump_client_state (__FUNCTION__);
+
+  /* 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 (debug_threads)
+	debug_printf ("%s:%d returning for waitee %d\n", __FUNCTION__, __LINE__, waitee_cs->file_desc);
       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)
 	{
-	  /* Has waitee/waiter been resolved? */
-	  if (csidx->packet_type == vContc)
+	  /* Found a vContc packet that is waiting */
+	  if (csidx->packet_type == vContc
+	      || csidx->last_packet_type == vContc)
 	    {
 	      char save_ch = ch;
 	      int waitee_has_bp, waiter_has_bp;
@@ -544,24 +623,28 @@ do_multiplexing (client_state *waitee_cs, char ch)
 		  waitee_has_bp = 1;
 		  waiter_has_bp = 1;
 		}
-	      else
+	      else		/* not exited */
 		{
+		  /* Does current client have a breakpoint at PC? */
 		  waitee_has_bp = has_client_breakpoint_at ((*the_target->read_pc)(get_thread_regcache (waitee_cs->ss->current_thread_, 1)));
 		  waiter_cs = set_client_state (csidx->file_desc);
+		  /* Does found client have a breakpoint at PC? */
 		  waiter_has_bp = has_client_breakpoint_at ((*the_target->read_pc)(get_thread_regcache (waiter_cs->ss->current_thread_, 1)));
 		  if (debug_threads)
 		    debug_printf ("%s:%d pc=%#lx waitee=%d has bp=%d waiter=%d has bp=%d\n", __FUNCTION__, __LINE__, (long unsigned)(*the_target->read_pc)(get_thread_regcache (waiter_cs->ss->current_thread_, 1)), waitee_cs->file_desc, waitee_has_bp, waiter_cs->file_desc, waiter_has_bp);
 		}
 	      if (waiter_has_bp)
 		{
-		  /* fake the reply to the waiter client */
+		  /* Belatedly reply to the waiter client */
 		  resolve_waiter (waiter_cs);
 		  if (waiter_cs->ss->last_status_.kind == TARGET_WAITKIND_EXITED)
-		    putpkt (waitee_cs->own_buffer_);	// Send the waitee W reply to vCont to the waiter
-		  csidx->pending = none_pending;
+		    /* Also send the waitee W reply to vCont to the waiter */
+		    putpkt (waitee_cs->own_buffer_);
 		  waitee_cs->pending = none_pending;
 		  if (!waitee_has_bp)
 		    waiter_cs->pending = pending_waitee;
+		  else
+		    waiter_cs->pending = none_pending;
 		}
 	      else if (debug_threads)
 		{
@@ -572,26 +655,32 @@ do_multiplexing (client_state *waitee_cs, char ch)
 		}
 	      ch = save_ch;
 	      waitee_cs = set_client_state (waitee_cs->file_desc);
+	      /* If the waitee did not reach the breakpoint then it needs to wait */
 	      if (!waitee_has_bp)
-		{
-		  waitee_cs->pending = pending_cont_waiter;
-		  return 0;
-		}
+		make_waitee_a_waiter = 1;
 	    }
-	}
-      else if (csidx->pending == pending_step_waiter)
-	{
-	  waiter_cs = set_client_state (csidx->file_desc);
-	  if (waitee_cs->packet_type == vConts
-	      || waitee_cs->packet_type == vContc)
+	  else if (csidx->pending == pending_step_waiter)
 	    {
-	      resolve_waiter (waiter_cs);
-	      waitee_cs->pending = csidx->pending = none_pending;
+	      waiter_cs = set_client_state (csidx->file_desc);
+	      if (waitee_cs->packet_type == vConts
+		  || waitee_cs->packet_type == vContc)
+		{
+		  resolve_waiter (waiter_cs);
+		  waitee_cs->pending = csidx->pending = none_pending;
+		}
+	      waitee_cs = set_client_state (waitee_cs->file_desc);
 	    }
-	  waitee_cs = set_client_state (waitee_cs->file_desc);
 	}
     }
-  return 1;
+  dump_client_state (__FUNCTION__);
+  if (make_waitee_a_waiter)
+    {
+      /* The packet will be replied to later in do_multiplexing */
+      waitee_cs->pending = pending_cont_waiter;
+      return 0;


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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2015-10-07 18:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-07 18:24 [SCM] scox/globalstate: Handle more than two clients more gracefully scox

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).