This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: linux native async mode support


A Friday 21 March 2008 15:54:37, Daniel Jacobowitz wrote:
>
> This is OK to commit now.  I'm sure we'll shake some more bugs out of
> it in the next few weeks :-)

Thanks!  I'm sure we will.  :-)

This is what I checked in after another round of testing
on x86_64-unknown-linux-gnu.

-- 
Pedro Alves
Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.9241
diff -u -p -r1.9241 ChangeLog
--- ChangeLog	21 Mar 2008 15:44:53 -0000	1.9241
+++ ChangeLog	21 Mar 2008 17:05:49 -0000
@@ -1,3 +1,105 @@
+2008-03-21  Pedro Alves  <pedro@codesourcery.com>
+
+	Linux native async support.
+
+	* target.h (struct target_ops): Delete to_async_mask_value and add
+	to_async_mask.
+	(target_is_async_p, target_async): Formatting.
+	(target_async_mask_value): Delete.
+	(target_async_mask): Delete function declaration, and add new
+	target macro with the same name.
+
+	* target.c (update_current_target): Replace to_async_mask_value by
+	to_async_mask.  Default to_async_mask to return_one.
+	(target_async_mask): Delete.
+	(find_default_can_async_p, find_default_is_async_p): New.
+	(init_dummy_target): register find_default_can_async_p and
+	find_default_is_async_p on the dummy target.
+
+	* linux-nat.c: Include inf-loop.h, event-loop.h and event-top.h.
+	(debug_linux_nat_async): New global.
+	(show_debug_linux_nat_async): New function.
+	(linux_nat_async_enabled, linux_nat_async_mask_value)
+	(linux_nat_event_pipe, linux_nat_num_queued_events)
+	(linux_nat_async_events_enabled): New globals.
+	(struct waitpid_result): New struct.
+	(waitpid_queue): New global.
+	(queued_waitpid, push_waitpid, drain_queued_events): New.
+	(my_waitpid): Call queued_waitpid.
+	(linux_child_follow_fork): Disable async events during the call.
+	(blocked_mask): Delete.
+	(sync_sigchld_action, async_sigchld_action): New globals.
+	(lin_lwp_attach_lwp): In sync mode, don't reblock SIGCHLD.  In
+	async mode, block events during the call.
+	(linux_nat_create_inferior): New.
+	(linux_nat_attach): In sync mode, restore the mask states.  In
+	async mode, wake the event loop immediatelly.
+	(detach_callback): Drain all queued events of the lwp we're
+	detaching from.
+	(linux_nat_detach): Block async mode, and drain events of the main
+	process.
+	(linux_nat_resume): If in async mode, mask async events during the
+	call.  If short circuiting, force event loop to wake up.  If
+	resuming, set target_executing, and register target events in the
+	event loop.
+	(pipe_to_local_event_queue, local_event_queue_to_pipe): New.
+	(linux_nat_wait): In async mode, block events during the call.
+	Only enable/disable passing SIGINT to the inferior in sync mode.
+	Get events from local waitpid queue.  If no interesting events was
+	found, return to events loop.  Reregister target events in the
+	event loop on exit.  In sync mode, no need to reblock SIGCHLD.
+	(linux_nat_kill): Disable events on entry.
+	(linux_nat_mourn_inferior): In sync mode, don't restore the masks
+	here.  Detach async mode from the event loop if there are no more
+	forks available, otherwise leave it on.
+	(sigchld_handler): Assure this is called only in sync mode.
+	(linux_async_permitted, linux_async_permitted_1): New globals.
+	(set_maintenance_linux_async_permitted)
+	(show_maintenance_linux_async_permitted): New functions.
+	(linux_nat_is_async_p, linux_nat_can_async_p)
+	(linux_nat_async_mask): New.
+	(linux_nat_event_pipe_pop, linux_nat_event_pipe_push): New.
+	(get_pending_events, async_sigchld_handler): New.
+	(linux_nat_async_events): New.
+	(async_terminal_is_ours): New global.
+	(linux_nat_terminal_inferior, linux_nat_terminal_ours): New.
+	(async_client_callback, async_client_context): New.
+	(linux_nat_async_file_handler, linux_nat_async)
+	(linux_nat_disable_async, linux_nat_enable_async): New.
+	(linux_nat_add_target): Register linux_nat_create_inferior,
+	linux_nat_can_async_p, linux_nat_is_async_p, linux_nat_async,
+	linux_nat_async_mask, linux_nat_terminal_inferior and
+	linux_nat_terminal_ours.
+	(_initialize_linux_nat): Remove local action variable, and update
+	code that used it to use sync_sigchld_action.  Add new
+	"lin-lwp-async" debug set/show command.  Put the "lin-lwp" debug
+	set/show command in the maintenance class.  Add new "linux-async"
+	maintenance set/show command.  Block SIGCHLD by default.  Setup
+	async_sichld_action, and sync_sigchld_action.  Install the default
+	async mode.
+	(lin_thread_get_thread_signals): Use a local sigset_t for blocking
+	the cancel signals.
+
+	* linux-thread-db.c (re_check_for_thread_db): New.
+	(clear_lwpid_callback): Handle TARGET_WAITKIND_IGNORE.
+	(thread_db_can_async_p, thread_db_is_async_p, thread_db_async)
+	(thread_db_async_mask): New.
+	(init_thread_db_ops): Register thread_db_can_async_p,
+	thread_db_is_async_p, thread_db_async and thread_db_async_mask.
+
+	* remote.c (remote_async_mask_value): New.
+	(remote_return_zero): New.
+	(init_remote_ops): Register remote_return_zero as callbacks of
+	to_can_async_p and to_is_async_p.
+	(remote_can_async_p, remote_is_async_p, remote_async): Update to
+	use remote_async_mask_value.
+	(remote_async_mask): New.
+	(init_remote_async_ops): Remove to_async_mask_value setting and
+	register remote_async_mask as to_async_mask callback in
+	remote_async_ops.
+
+	* Makefile.in (linux-nat.o): Update.
+
 2008-03-21  Daniel Jacobowitz  <dan@codesourcery.com>
 
 	* gdbthread.h (add_thread_with_info): New.
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.113
diff -u -p -r1.113 target.h
--- target.h	15 Mar 2008 14:55:21 -0000	1.113
+++ target.h	21 Mar 2008 17:05:49 -0000
@@ -414,9 +414,8 @@ struct target_ops
     /* ASYNC target controls */
     int (*to_can_async_p) (void);
     int (*to_is_async_p) (void);
-    void (*to_async) (void (*cb) (enum inferior_event_type, void *context),
-		      void *context);
-    int to_async_mask_value;
+    void (*to_async) (void (*) (enum inferior_event_type, void *), void *);
+    int (*to_async_mask) (int);
     int (*to_find_memory_regions) (int (*) (CORE_ADDR,
 					    unsigned long,
 					    int, int, int,
@@ -938,11 +937,11 @@ int target_follow_fork (int follow_child
 #define target_can_async_p() (current_target.to_can_async_p ())
 
 /* Is the target in asynchronous execution mode? */
-#define target_is_async_p() (current_target.to_is_async_p())
+#define target_is_async_p() (current_target.to_is_async_p ())
 
 /* Put the target in async mode with the specified callback function. */
 #define target_async(CALLBACK,CONTEXT) \
-     (current_target.to_async((CALLBACK), (CONTEXT)))
+     (current_target.to_async ((CALLBACK), (CONTEXT)))
 
 /* This is to be used ONLY within call_function_by_hand(). It provides
    a workaround, to have inferior function calls done in sychronous
@@ -958,10 +957,8 @@ int target_follow_fork (int follow_child
    the turning async on and off to the single execution commands,
    from where it is done currently, in remote_resume().  */
 
-#define	target_async_mask_value	\
-     (current_target.to_async_mask_value)
-
-extern int target_async_mask (int mask);
+#define target_async_mask(MASK)	\
+  (current_target.to_async_mask (MASK))
 
 /* Converts a process id to a string.  Usually, the string just contains
    `process xyz', but on some systems it may contain
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.157
diff -u -p -r1.157 target.c
--- target.c	15 Mar 2008 14:55:21 -0000	1.157
+++ target.c	21 Mar 2008 17:05:49 -0000
@@ -464,7 +464,7 @@ update_current_target (void)
       INHERIT (to_can_async_p, t);
       INHERIT (to_is_async_p, t);
       INHERIT (to_async, t);
-      INHERIT (to_async_mask_value, t);
+      INHERIT (to_async_mask, t);
       INHERIT (to_find_memory_regions, t);
       INHERIT (to_make_corefile_notes, t);
       INHERIT (to_get_thread_local_address, t);
@@ -637,6 +637,9 @@ update_current_target (void)
   de_fault (to_async,
 	    (void (*) (void (*) (enum inferior_event_type, void*), void*))
 	    tcomplain);
+  de_fault (to_async_mask,
+	    (int (*) (int))
+	    return_one);
   current_target.to_read_description = NULL;
 #undef de_fault
 
@@ -1694,14 +1697,6 @@ target_disconnect (char *args, int from_
   tcomplain ();
 }
 
-int
-target_async_mask (int mask)
-{
-  int saved_async_masked_status = target_async_mask_value;
-  target_async_mask_value = mask;
-  return saved_async_masked_status;
-}
-
 /* Look through the list of possible targets for a target that can
    follow forks.  */
 
@@ -1835,6 +1830,28 @@ find_default_create_inferior (char *exec
   return;
 }
 
+int
+find_default_can_async_p (void)
+{
+  struct target_ops *t;
+
+  t = find_default_run_target ("async");
+  if (t->to_can_async_p)
+    return (t->to_can_async_p) ();
+  return 0;
+}
+
+int
+find_default_is_async_p (void)
+{
+  struct target_ops *t;
+
+  t = find_default_run_target ("async");
+  if (t->to_is_async_p)
+    return (t->to_is_async_p) ();
+  return 0;
+}
+
 static int
 default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
 {
@@ -2099,6 +2116,8 @@ init_dummy_target (void)
   dummy_target.to_doc = "";
   dummy_target.to_attach = find_default_attach;
   dummy_target.to_create_inferior = find_default_create_inferior;
+  dummy_target.to_can_async_p = find_default_can_async_p;
+  dummy_target.to_is_async_p = find_default_is_async_p;
   dummy_target.to_pid_to_str = normal_pid_to_str;
   dummy_target.to_stratum = dummy_stratum;
   dummy_target.to_find_memory_regions = dummy_find_memory_regions;
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.77
diff -u -p -r1.77 linux-nat.c
--- linux-nat.c	21 Mar 2008 15:44:53 -0000	1.77
+++ linux-nat.c	21 Mar 2008 17:05:52 -0000
@@ -46,6 +46,9 @@
 #include "gdbthread.h"		/* for struct thread_info etc. */
 #include "gdb_stat.h"		/* for struct stat */
 #include <fcntl.h>		/* for O_RDONLY */
+#include "inf-loop.h"
+#include "event-loop.h"
+#include "event-top.h"
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
@@ -113,6 +116,15 @@ show_debug_linux_nat (struct ui_file *fi
 		    value);
 }
 
+static int debug_linux_nat_async = 0;
+static void
+show_debug_linux_nat_async (struct ui_file *file, int from_tty,
+			    struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Debugging of GNU/Linux async lwp module is %s.\n"),
+		    value);
+}
+
 static int linux_parent_pid;
 
 struct simple_pid_list
@@ -133,6 +145,158 @@ static int linux_supports_tracefork_flag
 
 static int linux_supports_tracevforkdone_flag = -1;
 
+/* Async mode support */
+
+/* To listen to target events asynchronously, we install a SIGCHLD
+   handler whose duty is to call waitpid (-1, ..., WNOHANG) to get all
+   the pending events into a pipe.  Whenever we're ready to handle
+   events asynchronously, this pipe is registered as the waitable file
+   handle in the event loop.  When we get to entry target points
+   coming out of the common code (target_wait, target_resume, ...),
+   that are going to call waitpid, we block SIGCHLD signals, and
+   remove all the events placed in the pipe into a local queue.  All
+   the subsequent calls to my_waitpid (a waitpid wrapper) check this
+   local queue first.  */
+
+/* True if async mode is currently on.  */
+static int linux_nat_async_enabled;
+
+/* Zero if the async mode, although enabled, is masked, which means
+   linux_nat_wait should behave as if async mode was off.  */
+static int linux_nat_async_mask_value = 1;
+
+/* The read/write ends of the pipe registered as waitable file in the
+   event loop.  */
+static int linux_nat_event_pipe[2] = { -1, -1 };
+
+/* Number of queued events in the pipe.  */
+static volatile int linux_nat_num_queued_events;
+
+/* If async mode is on, true if we're listening for events; false if
+   target events are blocked.  */
+static int linux_nat_async_events_enabled;
+
+static int linux_nat_async_events (int enable);
+static void pipe_to_local_event_queue (void);
+static void local_event_queue_to_pipe (void);
+static void linux_nat_event_pipe_push (int pid, int status, int options);
+static int linux_nat_event_pipe_pop (int* ptr_status, int* ptr_options);
+static void linux_nat_set_async_mode (int on);
+static void linux_nat_async (void (*callback)
+			     (enum inferior_event_type event_type, void *context),
+			     void *context);
+static int linux_nat_async_mask (int mask);
+
+/* Captures the result of a successful waitpid call, along with the
+   options used in that call.  */
+struct waitpid_result
+{
+  int pid;
+  int status;
+  int options;
+  struct waitpid_result *next;
+};
+
+/* A singly-linked list of the results of the waitpid calls performed
+   in the async SIGCHLD handler.  */
+static struct waitpid_result *waitpid_queue = NULL;
+
+static int
+queued_waitpid (int pid, int *status, int flags)
+{
+  struct waitpid_result *msg = waitpid_queue, *prev = NULL;
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog,
+			"\
+QWPID: linux_nat_async_events_enabled(%d), linux_nat_num_queued_events(%d)\n",
+			linux_nat_async_events_enabled,
+			linux_nat_num_queued_events);
+
+  if (flags & __WALL)
+    {
+      for (; msg; prev = msg, msg = msg->next)
+	if (pid == -1 || pid == msg->pid)
+	  break;
+    }
+  else if (flags & __WCLONE)
+    {
+      for (; msg; prev = msg, msg = msg->next)
+	if (msg->options & __WCLONE
+	    && (pid == -1 || pid == msg->pid))
+	  break;
+    }
+  else
+    {
+      for (; msg; prev = msg, msg = msg->next)
+	if ((msg->options & __WCLONE) == 0
+	    && (pid == -1 || pid == msg->pid))
+	  break;
+    }
+
+  if (msg)
+    {
+      int pid;
+
+      if (prev)
+	prev->next = msg->next;
+      else
+	waitpid_queue = msg->next;
+
+      msg->next = NULL;
+      if (status)
+	*status = msg->status;
+      pid = msg->pid;
+
+      if (debug_linux_nat_async)
+	fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n",
+			    pid, msg->status);
+      xfree (msg);
+
+      return pid;
+    }
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "QWPID: miss\n");
+
+  if (status)
+    *status = 0;
+  return -1;
+}
+
+static void
+push_waitpid (int pid, int status, int options)
+{
+  struct waitpid_result *event, *new_event;
+
+  new_event = xmalloc (sizeof (*new_event));
+  new_event->pid = pid;
+  new_event->status = status;
+  new_event->options = options;
+  new_event->next = NULL;
+
+  if (waitpid_queue)
+    {
+      for (event = waitpid_queue;
+	   event && event->next;
+	   event = event->next)
+	;
+
+      event->next = new_event;
+    }
+  else
+    waitpid_queue = new_event;
+}
+
+/* Drain all queued event of PID.  If PID is -1, the effect is of
+   draining all events.  */
+static void
+drain_queued_events (int pid)
+{
+  while (queued_waitpid (pid, NULL, __WALL) != -1)
+    ;
+}
+
 
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -183,12 +347,21 @@ linux_tracefork_child (void)
   _exit (0);
 }
 
-/* Wrapper function for waitpid which handles EINTR.  */
+/* Wrapper function for waitpid which handles EINTR, and checks for
+   locally queued events.  */
 
 static int
 my_waitpid (int pid, int *status, int flags)
 {
   int ret;
+
+  /* There should be no concurrent calls to waitpid.  */
+  gdb_assert (!linux_nat_async_events_enabled);
+
+  ret = queued_waitpid (pid, status, flags);
+  if (ret != -1)
+    return ret;
+
   do
     {
       ret = waitpid (pid, status, flags);
@@ -362,6 +535,9 @@ linux_child_follow_fork (struct target_o
   int has_vforked;
   int parent_pid, child_pid;
 
+  if (target_can_async_p ())
+    target_async (NULL, 0);
+
   get_last_target_status (&last_ptid, &last_status);
   has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
   parent_pid = ptid_get_lwp (last_ptid);
@@ -506,9 +682,7 @@ linux_child_follow_fork (struct target_o
 	  fork_save_infrun_state (fp, 0);
 	}
       else
-	{
-	  target_detach (NULL, 0);
-	}
+	target_detach (NULL, 0);
 
       inferior_ptid = ptid_build (child_pid, child_pid, 0);
 
@@ -523,6 +697,9 @@ linux_child_follow_fork (struct target_o
       follow_inferior_reset_breakpoints ();
     }
 
+  if (target_can_async_p ())
+    target_async (inferior_event_handler, 0);
+
   return 0;
 }
 
@@ -611,8 +788,11 @@ static sigset_t normal_mask;
    _initialize_linux_nat.  */
 static sigset_t suspend_mask;
 
-/* Signals to block to make that sigsuspend work.  */
-static sigset_t blocked_mask;
+/* SIGCHLD action for synchronous mode.  */
+struct sigaction sync_sigchld_action;
+
+/* SIGCHLD action for asynchronous mode.  */
+static struct sigaction async_sigchld_action;
 
 
 /* Prototypes for local functions.  */
@@ -837,16 +1017,12 @@ int
 lin_lwp_attach_lwp (ptid_t ptid)
 {
   struct lwp_info *lp;
+  int async_events_were_enabled = 0;
 
   gdb_assert (is_lwp (ptid));
 
-  /* Make sure SIGCHLD is blocked.  We don't want SIGCHLD events
-     to interrupt either the ptrace() or waitpid() calls below.  */
-  if (!sigismember (&blocked_mask, SIGCHLD))
-    {
-      sigaddset (&blocked_mask, SIGCHLD);
-      sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
-    }
+  if (target_can_async_p ())
+    async_events_were_enabled = linux_nat_async_events (0);
 
   lp = find_lwp_pid (ptid);
 
@@ -919,10 +1095,39 @@ lin_lwp_attach_lwp (ptid_t ptid)
       lp->stopped = 1;
     }
 
+  if (async_events_were_enabled)
+    linux_nat_async_events (1);
+
   return 0;
 }
 
 static void
+linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
+			   int from_tty)
+{
+  int saved_async = 0;
+
+  /* The fork_child mechanism is synchronous and calls target_wait, so
+     we have to mask the async mode.  */
+
+  if (target_can_async_p ())
+    saved_async = linux_nat_async_mask (0);
+  else
+    {
+      /* Restore the original signal mask.  */
+      sigprocmask (SIG_SETMASK, &normal_mask, NULL);
+      /* Make sure we don't block SIGCHLD during a sigsuspend.  */
+      suspend_mask = normal_mask;
+      sigdelset (&suspend_mask, SIGCHLD);
+    }
+
+  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+
+  if (saved_async)
+    linux_nat_async_mask (saved_async);
+}
+
+static void
 linux_nat_attach (char *args, int from_tty)
 {
   struct lwp_info *lp;
@@ -934,6 +1139,15 @@ linux_nat_attach (char *args, int from_t
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
+  if (!target_can_async_p ())
+    {
+      /* Restore the original signal mask.  */
+      sigprocmask (SIG_SETMASK, &normal_mask, NULL);
+      /* Make sure we don't block SIGCHLD during a sigsuspend.  */
+      suspend_mask = normal_mask;
+      sigdelset (&suspend_mask, SIGCHLD);
+    }
+
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
@@ -961,9 +1175,14 @@ linux_nat_attach (char *args, int from_t
   lp->status = W_STOPCODE (SIGSTOP);
   lp->resumed = 1;
   if (debug_linux_nat)
+    fprintf_unfiltered (gdb_stdlog,
+			"LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+  if (target_can_async_p ())
     {
-      fprintf_unfiltered (gdb_stdlog,
-			  "LLA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+      /* Wake event loop with special token, to get to WFI.  */
+      linux_nat_event_pipe_push (-1, -1, -1);
+      /* Register in the event loop.  */
+      target_async (inferior_event_handler, 0);
     }
 }
 
@@ -1020,6 +1239,7 @@ detach_callback (struct lwp_info *lp, vo
 			    target_pid_to_str (lp->ptid),
 			    strsignal (WSTOPSIG (lp->status)));
 
+      drain_queued_events (GET_LWP (lp->ptid));
       delete_lwp (lp->ptid);
     }
 
@@ -1029,6 +1249,10 @@ detach_callback (struct lwp_info *lp, vo
 static void
 linux_nat_detach (char *args, int from_tty)
 {
+  int pid;
+  if (target_can_async_p ())
+    linux_nat_async (NULL, 0);
+
   iterate_over_lwps (detach_callback, NULL);
 
   /* Only the initial process should be left right now.  */
@@ -1039,12 +1263,12 @@ linux_nat_detach (char *args, int from_t
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
-  /* Restore the original signal mask.  */
-  sigprocmask (SIG_SETMASK, &normal_mask, NULL);
-  sigemptyset (&blocked_mask);
-
-  inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
+  pid = GET_PID (inferior_ptid);
+  inferior_ptid = pid_to_ptid (pid);
   linux_ops->to_detach (args, from_tty);
+
+  if (target_can_async_p ())
+    drain_queued_events (pid);
 }
 
 /* Resume LP.  */
@@ -1098,6 +1322,10 @@ linux_nat_resume (ptid_t ptid, int step,
 
   prune_lwps ();
 
+  if (target_can_async_p ())
+    /* Block events while we're here.  */
+    linux_nat_async_events (0);
+
   /* A specific PTID means `step only this process id'.  */
   resume_all = (PIDGET (ptid) == -1);
 
@@ -1162,6 +1390,13 @@ linux_nat_resume (ptid_t ptid, int step,
 			    "LLR: Short circuiting for status 0x%x\n",
 			    lp->status);
 
+      if (target_can_async_p ())
+	{
+	  /* Wake event loop with special token, to get to WFI.  */
+	  linux_nat_event_pipe_push (-1, -1, -1);
+
+	  target_async (inferior_event_handler, 0);
+	}
       return;
     }
 
@@ -1181,6 +1416,12 @@ linux_nat_resume (ptid_t ptid, int step,
 			step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
 			target_pid_to_str (ptid),
 			signo ? strsignal (signo) : "0");
+
+  if (target_can_async_p ())
+    {
+      target_executing = 1;
+      target_async (inferior_event_handler, 0);
+    }
 }
 
 /* Issue kill to specified lwp.  */
@@ -2032,6 +2273,57 @@ linux_nat_filter_event (int lwpid, int s
   return lp;
 }
 
+/* Get the events stored in the pipe into the local queue, so they are
+   accessible to queued_waitpid.  We need to do this, since it is not
+   always the case that the event at the head of the pipe is the event
+   we want.  */
+
+static void
+pipe_to_local_event_queue (void)
+{
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog,
+			"PTLEQ: linux_nat_num_queued_events(%d)\n",
+			linux_nat_num_queued_events);
+  while (linux_nat_num_queued_events)
+    {
+      int lwpid, status, options;
+
+      lwpid = linux_nat_event_pipe_pop (&status, &options);
+      if (lwpid == -1 && status == -1 && options == -1)
+	/* Special wake up event loop token.  */
+	continue;
+
+      gdb_assert (lwpid > 0);
+      push_waitpid (lwpid, status, options);
+    }
+}
+
+/* Get the unprocessed events stored in the local queue back into the
+   pipe, so the event loop realizes there's something else to
+   process.  */
+
+static void
+local_event_queue_to_pipe (void)
+{
+  struct waitpid_result *w = waitpid_queue;
+  while (w)
+    {
+      struct waitpid_result *next = w->next;
+      linux_nat_event_pipe_push (w->pid,
+				 w->status,
+				 w->options);
+      xfree (w);
+      w = next;
+    }
+  waitpid_queue = NULL;
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog,
+			"LEQTP: linux_nat_num_queued_events(%d)\n",
+			linux_nat_num_queued_events);
+}
+
 static ptid_t
 linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 {
@@ -2041,6 +2333,9 @@ linux_nat_wait (ptid_t ptid, struct targ
   pid_t pid = PIDGET (ptid);
   sigset_t flush_mask;
 
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "LLW: enter\n");
+
   /* The first time we get here after starting a new inferior, we may
      not have added it to the LWP list yet - this is the earliest
      moment at which we know its PID.  */
@@ -2056,12 +2351,9 @@ linux_nat_wait (ptid_t ptid, struct targ
 
   sigemptyset (&flush_mask);
 
-  /* Make sure SIGCHLD is blocked.  */
-  if (!sigismember (&blocked_mask, SIGCHLD))
-    {
-      sigaddset (&blocked_mask, SIGCHLD);
-      sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
-    }
+  if (target_can_async_p ())
+    /* Block events while we're here.  */
+    target_async (NULL, 0);
 
 retry:
 
@@ -2085,7 +2377,7 @@ retry:
 				target_pid_to_str (lp->ptid));
 	}
 
-      /* But if we don't fine one, we'll have to wait, and check both
+      /* But if we don't find one, we'll have to wait, and check both
          cloned and uncloned processes.  We start with the cloned
          processes.  */
       options = __WCLONE | WNOHANG;
@@ -2144,15 +2436,24 @@ retry:
       stop_wait_callback (lp, NULL);
     }
 
-  set_sigint_trap ();		/* Causes SIGINT to be passed on to the
-				   attached process. */
-  set_sigio_trap ();
+  if (!target_can_async_p ())
+    {
+      /* Causes SIGINT to be passed on to the attached process.  */
+      set_sigint_trap ();
+      set_sigio_trap ();
+    }
 
   while (status == 0)
     {
       pid_t lwpid;
 
-      lwpid = my_waitpid (pid, &status, options);
+      if (target_can_async_p ())
+	/* In async mode, don't ever block.  Only look at the locally
+	   queued events.  */
+	lwpid = queued_waitpid (pid, &status, options);
+      else
+	lwpid = my_waitpid (pid, &status, options);
+
       if (lwpid > 0)
 	{
 	  gdb_assert (pid == -1 || lwpid == pid);
@@ -2180,17 +2481,38 @@ retry:
 	  /* Alternate between checking cloned and uncloned processes.  */
 	  options ^= __WCLONE;
 
-	  /* And suspend every time we have checked both.  */
+	  /* And every time we have checked both:
+	     In async mode, return to event loop;
+	     In sync mode, suspend waiting for a SIGCHLD signal.  */
 	  if (options & __WCLONE)
-	    sigsuspend (&suspend_mask);
+	    {
+	      if (target_can_async_p ())
+		{
+		  /* No interesting event.  */
+		  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+
+		  /* Get ready for the next event.  */
+		  target_async (inferior_event_handler, 0);
+
+		  if (debug_linux_nat_async)
+		    fprintf_unfiltered (gdb_stdlog, "LLW: exit (ignore)\n");
+
+		  return minus_one_ptid;
+		}
+
+	      sigsuspend (&suspend_mask);
+	    }
 	}
 
       /* We shouldn't end up here unless we want to try again.  */
       gdb_assert (status == 0);
     }
 
-  clear_sigio_trap ();
-  clear_sigint_trap ();
+  if (!target_can_async_p ())
+    {
+      clear_sigio_trap ();
+      clear_sigint_trap ();
+    }
 
   gdb_assert (lp);
 
@@ -2287,6 +2609,13 @@ retry:
   else
     store_waitstatus (ourstatus, status);
 
+  /* Get ready for the next event.  */
+  if (target_can_async_p ())
+    target_async (inferior_event_handler, 0);
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "LLW: exit\n");
+
   return lp->ptid;
 }
 
@@ -2366,6 +2695,9 @@ linux_nat_kill (void)
   ptid_t last_ptid;
   int status;
 
+  if (target_can_async_p ())
+    target_async (NULL, 0);
+
   /* If we're stopped while forking and we haven't followed yet,
      kill the other task.  We need to do this first because the
      parent will be sleeping if this is a vfork.  */
@@ -2380,7 +2712,10 @@ linux_nat_kill (void)
     }
 
   if (forks_exist_p ())
-    linux_fork_killall ();
+    {
+      linux_fork_killall ();
+      drain_queued_events (-1);
+    }
   else
     {
       /* Kill all LWP's ...  */
@@ -2401,13 +2736,13 @@ linux_nat_mourn_inferior (void)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
-  /* Restore the original signal mask.  */
-  sigprocmask (SIG_SETMASK, &normal_mask, NULL);
-  sigemptyset (&blocked_mask);
-
   if (! forks_exist_p ())
-    /* Normal case, no other forks available.  */
-    linux_ops->to_mourn_inferior ();
+    {
+      /* Normal case, no other forks available.  */
+      if (target_can_async_p ())
+	linux_nat_async (NULL, 0);
+      linux_ops->to_mourn_inferior ();
+    }
   else
     /* Multi-fork case.  The current inferior_ptid has exited, but
        there are other viable forks to debug.  Delete the exiting
@@ -2475,6 +2810,13 @@ linux_nat_pid_to_str (ptid_t ptid)
 static void
 sigchld_handler (int signo)
 {
+  if (linux_nat_async_enabled
+      && linux_nat_async_events_enabled
+      && signo == SIGCHLD)
+    /* It is *always* a bug to hit this.  */
+    internal_error (__FILE__, __LINE__,
+		    "sigchld_handler called when async events are enabled");
+
   /* Do nothing.  The only reason for this handler is that it allows
      us to use sigsuspend in linux_nat_wait above to wait for the
      arrival of a SIGCHLD.  */
@@ -3233,6 +3575,376 @@ linux_trad_target (CORE_ADDR (*register_
   return t;
 }
 
+/* Controls if async mode is permitted.  */
+static int linux_async_permitted = 0;
+
+/* The set command writes to this variable.  If the inferior is
+   executing, linux_nat_async_permitted is *not* updated.  */
+static int linux_async_permitted_1 = 0;
+
+static void
+set_maintenance_linux_async_permitted (char *args, int from_tty,
+			       struct cmd_list_element *c)
+{
+  if (target_has_execution)
+    {
+      linux_async_permitted_1 = linux_async_permitted;
+      error (_("Cannot change this setting while the inferior is running."));
+    }
+
+  linux_async_permitted = linux_async_permitted_1;
+  linux_nat_set_async_mode (linux_async_permitted);
+}
+
+static void
+show_maintenance_linux_async_permitted (struct ui_file *file, int from_tty,
+			    struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("\
+Controlling the GNU/Linux inferior in asynchronous mode is %s.\n"),
+		    value);
+}
+
+/* target_is_async_p implementation.  */
+
+static int
+linux_nat_is_async_p (void)
+{
+  /* NOTE: palves 2008-03-21: We're only async when the user requests
+     it explicitly with the "maintenance set linux-async" command.
+     Someday, linux will always be async.  */
+  if (!linux_async_permitted)
+    return 0;
+
+  return 1;
+}
+
+/* target_can_async_p implementation.  */
+
+static int
+linux_nat_can_async_p (void)
+{
+  /* NOTE: palves 2008-03-21: We're only async when the user requests
+     it explicitly with the "maintenance set linux-async" command.
+     Someday, linux will always be async.  */
+  if (!linux_async_permitted)
+    return 0;
+
+  /* See target.h/target_async_mask.  */
+  return linux_nat_async_mask_value;
+}
+
+/* target_async_mask implementation.  */
+
+static int
+linux_nat_async_mask (int mask)
+{
+  int current_state;
+  current_state = linux_nat_async_mask_value;
+
+  if (current_state != mask)
+    {
+      if (mask == 0)
+	{
+	  linux_nat_async (NULL, 0);
+	  linux_nat_async_mask_value = mask;
+	  /* We're in sync mode.  Make sure SIGCHLD isn't handled by
+	     async_sigchld_handler when we come out of sigsuspend in
+	     linux_nat_wait.  */
+	  sigaction (SIGCHLD, &sync_sigchld_action, NULL);
+	}
+      else
+	{
+	  /* Restore the async handler.  */
+	  sigaction (SIGCHLD, &async_sigchld_action, NULL);
+	  linux_nat_async_mask_value = mask;
+	  linux_nat_async (inferior_event_handler, 0);
+	}
+    }
+
+  return current_state;
+}
+
+/* Pop an event from the event pipe.  */
+
+static int
+linux_nat_event_pipe_pop (int* ptr_status, int* ptr_options)
+{
+  struct waitpid_result event = {0};
+  int ret;
+
+  do
+    {
+      ret = read (linux_nat_event_pipe[0], &event, sizeof (event));
+    }
+  while (ret == -1 && errno == EINTR);
+
+  gdb_assert (ret == sizeof (event));
+
+  *ptr_status = event.status;
+  *ptr_options = event.options;
+
+  linux_nat_num_queued_events--;
+
+  return event.pid;
+}
+
+/* Push an event into the event pipe.  */
+
+static void
+linux_nat_event_pipe_push (int pid, int status, int options)
+{
+  int ret;
+  struct waitpid_result event = {0};
+  event.pid = pid;
+  event.status = status;
+  event.options = options;
+
+  do
+    {
+      ret = write (linux_nat_event_pipe[1], &event, sizeof (event));
+      gdb_assert ((ret == -1 && errno == EINTR) || ret == sizeof (event));
+    } while (ret == -1 && errno == EINTR);
+
+  linux_nat_num_queued_events++;
+}
+
+static void
+get_pending_events (void)
+{
+  int status, options, pid;
+
+  if (!linux_nat_async_enabled || !linux_nat_async_events_enabled)
+    internal_error (__FILE__, __LINE__,
+		    "get_pending_events called with async masked");
+
+  while (1)
+    {
+      status = 0;
+      options = __WCLONE | WNOHANG;
+
+      do
+	{
+	  pid = waitpid (-1, &status, options);
+	}
+      while (pid == -1 && errno == EINTR);
+
+      if (pid <= 0)
+	{
+	  options = WNOHANG;
+	  do
+	    {
+	      pid = waitpid (-1, &status, options);
+	    }
+	  while (pid == -1 && errno == EINTR);
+	}
+
+      if (pid <= 0)
+	/* No more children reporting events.  */
+	break;
+
+      if (debug_linux_nat_async)
+	fprintf_unfiltered (gdb_stdlog, "\
+get_pending_events: pid(%d), status(%x), options (%x)\n",
+			    pid, status, options);
+
+      linux_nat_event_pipe_push (pid, status, options);
+    }
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "\
+get_pending_events: linux_nat_num_queued_events(%d)\n",
+			linux_nat_num_queued_events);
+}
+
+/* SIGCHLD handler for async mode.  */
+
+static void
+async_sigchld_handler (int signo)
+{
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "async_sigchld_handler\n");
+
+  get_pending_events ();
+}
+
+/* Enable or disable async SIGCHLD handling.  */
+
+static int
+linux_nat_async_events (int enable)
+{
+  int current_state = linux_nat_async_events_enabled;
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog,
+			"LNAE: enable(%d): linux_nat_async_events_enabled(%d), "
+			"linux_nat_num_queued_events(%d)\n",
+			enable, linux_nat_async_events_enabled,
+			linux_nat_num_queued_events);
+
+  if (current_state != enable)
+    {
+      sigset_t mask;
+      sigemptyset (&mask);
+      sigaddset (&mask, SIGCHLD);
+      if (enable)
+	{
+	  /* Unblock target events.  */
+	  linux_nat_async_events_enabled = 1;
+
+	  local_event_queue_to_pipe ();
+	  /* While in masked async, we may have not collected all the
+	     pending events.  Get them out now.  */
+	  get_pending_events ();
+	  sigprocmask (SIG_UNBLOCK, &mask, NULL);
+	}
+      else
+	{
+	  /* Block target events.  */
+	  sigprocmask (SIG_BLOCK, &mask, NULL);
+	  linux_nat_async_events_enabled = 0;
+	  /* Get events out of queue, and make them available to
+	     queued_waitpid / my_waitpid.  */
+	  pipe_to_local_event_queue ();
+	}
+    }
+
+  return current_state;
+}
+
+static int async_terminal_is_ours = 1;
+
+/* target_terminal_inferior implementation.  */
+
+static void
+linux_nat_terminal_inferior (void)
+{
+  if (!target_is_async_p ())
+    {
+      /* Async mode is disabled.  */
+      terminal_inferior ();
+      return;
+    }
+
+  /* GDB should never give the terminal to the inferior, if the
+     inferior is running in the background (run&, continue&, etc.).
+     This check can be removed when the common code is fixed.  */
+  if (!sync_execution)
+    return;
+
+  terminal_inferior ();
+
+  if (!async_terminal_is_ours)
+    return;
+
+  delete_file_handler (input_fd);
+  async_terminal_is_ours = 0;
+  set_sigint_trap ();
+}
+
+/* target_terminal_ours implementation.  */
+
+void
+linux_nat_terminal_ours (void)
+{
+  if (!target_is_async_p ())
+    {
+      /* Async mode is disabled.  */
+      terminal_ours ();
+      return;
+    }
+
+  /* GDB should never give the terminal to the inferior if the
+     inferior is running in the background (run&, continue&, etc.),
+     but claiming it sure should.  */
+  terminal_ours ();
+
+  if (!sync_execution)
+    return;
+
+  if (async_terminal_is_ours)
+    return;
+
+  clear_sigint_trap ();
+  add_file_handler (input_fd, stdin_event_handler, 0);
+  async_terminal_is_ours = 1;
+}
+
+static void (*async_client_callback) (enum inferior_event_type event_type,
+				      void *context);
+static void *async_client_context;
+
+static void
+linux_nat_async_file_handler (int error, gdb_client_data client_data)
+{
+  async_client_callback (INF_REG_EVENT, async_client_context);
+}
+
+/* target_async implementation.  */
+
+static void
+linux_nat_async (void (*callback) (enum inferior_event_type event_type,
+				   void *context), void *context)
+{
+  if (linux_nat_async_mask_value == 0 || !linux_nat_async_enabled)
+    internal_error (__FILE__, __LINE__,
+		    "Calling target_async when async is masked");
+
+  if (callback != NULL)
+    {
+      async_client_callback = callback;
+      async_client_context = context;
+      add_file_handler (linux_nat_event_pipe[0],
+			linux_nat_async_file_handler, NULL);
+
+      linux_nat_async_events (1);
+    }
+  else
+    {
+      async_client_callback = callback;
+      async_client_context = context;
+
+      linux_nat_async_events (0);
+      delete_file_handler (linux_nat_event_pipe[0]);
+    }
+  return;
+}
+
+/* Enable/Disable async mode.  */
+
+static void
+linux_nat_set_async_mode (int on)
+{
+  if (linux_nat_async_enabled != on)
+    {
+      if (on)
+	{
+	  gdb_assert (waitpid_queue == NULL);
+	  sigaction (SIGCHLD, &async_sigchld_action, NULL);
+
+	  if (pipe (linux_nat_event_pipe) == -1)
+	    internal_error (__FILE__, __LINE__,
+			    "creating event pipe failed.");
+
+	  fcntl (linux_nat_event_pipe[0], F_SETFL, O_NONBLOCK);
+	  fcntl (linux_nat_event_pipe[1], F_SETFL, O_NONBLOCK);
+	}
+      else
+	{
+	  sigaction (SIGCHLD, &sync_sigchld_action, NULL);
+
+	  drain_queued_events (-1);
+
+	  linux_nat_num_queued_events = 0;
+	  close (linux_nat_event_pipe[0]);
+	  close (linux_nat_event_pipe[1]);
+	  linux_nat_event_pipe[0] = linux_nat_event_pipe[1] = -1;
+
+	}
+    }
+  linux_nat_async_enabled = on;
+}
+
 void
 linux_nat_add_target (struct target_ops *t)
 {
@@ -3244,6 +3956,7 @@ linux_nat_add_target (struct target_ops 
   linux_ops = &linux_ops_saved;
 
   /* Override some methods for multithreading.  */
+  t->to_create_inferior = linux_nat_create_inferior;
   t->to_attach = linux_nat_attach;
   t->to_detach = linux_nat_detach;
   t->to_resume = linux_nat_resume;
@@ -3255,6 +3968,13 @@ linux_nat_add_target (struct target_ops 
   t->to_pid_to_str = linux_nat_pid_to_str;
   t->to_has_thread_control = tc_schedlock;
 
+  t->to_can_async_p = linux_nat_can_async_p;
+  t->to_is_async_p = linux_nat_is_async_p;
+  t->to_async = linux_nat_async;
+  t->to_async_mask = linux_nat_async_mask;
+  t->to_terminal_inferior = linux_nat_terminal_inferior;
+  t->to_terminal_ours = linux_nat_terminal_ours;
+
   /* We don't change the stratum; this target will sit at
      process_stratum and thread_db will set at thread_stratum.  This
      is a little strange, since this is a multi-threaded-capable
@@ -3292,7 +4012,7 @@ linux_nat_get_siginfo (ptid_t ptid)
 void
 _initialize_linux_nat (void)
 {
-  struct sigaction action;
+  sigset_t mask;
 
   add_info ("proc", linux_nat_info_proc_cmd, _("\
 Show /proc process information about any running process.\n\
@@ -3303,27 +4023,63 @@ Specify any of the following keywords fo
   status   -- list a different bunch of random process info.\n\
   all      -- list all available /proc info."));
 
-  /* Save the original signal mask.  */
+  add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
+			    &debug_linux_nat, _("\
+Set debugging of GNU/Linux lwp module."), _("\
+Show debugging of GNU/Linux lwp module."), _("\
+Enables printf debugging output."),
+			    NULL,
+			    show_debug_linux_nat,
+			    &setdebuglist, &showdebuglist);
+
+  add_setshow_zinteger_cmd ("lin-lwp-async", class_maintenance,
+			    &debug_linux_nat_async, _("\
+Set debugging of GNU/Linux async lwp module."), _("\
+Show debugging of GNU/Linux async lwp module."), _("\
+Enables printf debugging output."),
+			    NULL,
+			    show_debug_linux_nat_async,
+			    &setdebuglist, &showdebuglist);
+
+  add_setshow_boolean_cmd ("linux-async", class_maintenance,
+			   &linux_async_permitted_1, _("\
+Set whether gdb controls the GNU/Linux inferior in asynchronous mode."), _("\
+Show whether gdb controls the GNU/Linux inferior in asynchronous mode."), _("\
+Tells gdb whether to control the GNU/Linux inferior in asynchronous mode."),
+			   set_maintenance_linux_async_permitted,
+			   show_maintenance_linux_async_permitted,
+			   &maintenance_set_cmdlist,
+			   &maintenance_show_cmdlist);
+
+  /* Block SIGCHLD by default.  Doing this early prevents it getting
+     unblocked if an exception is thrown due to an error while the
+     inferior is starting (sigsetjmp/siglongjmp).  */
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGCHLD);
+  sigprocmask (SIG_BLOCK, &mask, NULL);
+
+  /* Save this mask as the default.  */
   sigprocmask (SIG_SETMASK, NULL, &normal_mask);
 
-  action.sa_handler = sigchld_handler;
-  sigemptyset (&action.sa_mask);
-  action.sa_flags = SA_RESTART;
-  sigaction (SIGCHLD, &action, NULL);
+  /* The synchronous SIGCHLD handler.  */
+  sync_sigchld_action.sa_handler = sigchld_handler;
+  sigemptyset (&sync_sigchld_action.sa_mask);
+  sync_sigchld_action.sa_flags = SA_RESTART;
+
+  /* Make it the default.  */
+  sigaction (SIGCHLD, &sync_sigchld_action, NULL);
 
   /* Make sure we don't block SIGCHLD during a sigsuspend.  */
   sigprocmask (SIG_SETMASK, NULL, &suspend_mask);
   sigdelset (&suspend_mask, SIGCHLD);
 
-  sigemptyset (&blocked_mask);
+  /* SIGCHLD handler for async mode.  */
+  async_sigchld_action.sa_handler = async_sigchld_handler;
+  sigemptyset (&async_sigchld_action.sa_mask);
+  async_sigchld_action.sa_flags = SA_RESTART;
 
-  add_setshow_zinteger_cmd ("lin-lwp", no_class, &debug_linux_nat, _("\
-Set debugging of GNU/Linux lwp module."), _("\
-Show debugging of GNU/Linux lwp module."), _("\
-Enables printf debugging output."),
-			    NULL,
-			    show_debug_linux_nat,
-			    &setdebuglist, &showdebuglist);
+  /* Install the default mode.  */
+  linux_nat_set_async_mode (linux_async_permitted);
 }
 
 
@@ -3359,7 +4115,9 @@ lin_thread_get_thread_signals (sigset_t 
 {
   struct sigaction action;
   int restart, cancel;
+  sigset_t blocked_mask;
 
+  sigemptyset (&blocked_mask);
   sigemptyset (set);
 
   restart = get_signo ("__pthread_sig_restart");
Index: linux-thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-thread-db.c,v
retrieving revision 1.38
diff -u -p -r1.38 linux-thread-db.c
--- linux-thread-db.c	21 Mar 2008 15:44:53 -0000	1.38
+++ linux-thread-db.c	21 Mar 2008 17:05:52 -0000
@@ -824,6 +824,9 @@ thread_db_wait (ptid_t ptid, struct targ
 
   ptid = target_beneath->to_wait (ptid, ourstatus);
 
+  if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
+    return ptid;
+
   if (ourstatus->kind == TARGET_WAITKIND_EXITED
     || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
     return pid_to_ptid (-1);
@@ -885,6 +888,31 @@ thread_db_mourn_inferior (void)
 }
 
 static int
+thread_db_can_async_p (void)
+{
+  return target_beneath->to_can_async_p ();
+}
+
+static int
+thread_db_is_async_p (void)
+{
+  return target_beneath->to_is_async_p ();
+}
+
+static void
+thread_db_async (void (*callback) (enum inferior_event_type event_type,
+				   void *context), void *context)
+{
+  return target_beneath->to_async (callback, context);
+}
+
+static int
+thread_db_async_mask (int mask)
+{
+  return target_beneath->to_async_mask (mask);
+}
+
+static int
 find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
 {
   td_thrinfo_t ti;
@@ -1056,6 +1084,10 @@ init_thread_db_ops (void)
   thread_db_ops.to_get_thread_local_address
     = thread_db_get_thread_local_address;
   thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info;
+  thread_db_ops.to_can_async_p = thread_db_can_async_p;
+  thread_db_ops.to_is_async_p = thread_db_is_async_p;
+  thread_db_ops.to_async = thread_db_async;
+  thread_db_ops.to_async_mask = thread_db_async_mask;
   thread_db_ops.to_magic = OPS_MAGIC;
 }
 
Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.285
diff -u -p -r1.285 remote.c
--- remote.c	14 Mar 2008 18:57:43 -0000	1.285
+++ remote.c	21 Mar 2008 17:05:53 -0000
@@ -481,6 +481,8 @@ static struct target_ops extended_remote
    extended_remote_ops, but with asynchronous support.  */
 static struct target_ops remote_async_ops;
 
+static int remote_async_mask_value = 1;
+
 static struct target_ops extended_async_remote_ops;
 
 /* FIXME: cagney/1999-09-23: Even though getpkt was called with
@@ -7176,6 +7178,12 @@ remote_command (char *args, int from_tty
   help_list (remote_cmdlist, "remote ", -1, gdb_stdout);
 }
 
+static int
+remote_return_zero (void)
+{
+  return 0;
+}
+
 static void
 init_remote_ops (void)
 {
@@ -7229,6 +7237,8 @@ Specify the serial device it is connecte
   remote_ops.to_flash_erase = remote_flash_erase;
   remote_ops.to_flash_done = remote_flash_done;
   remote_ops.to_read_description = remote_read_description;
+  remote_ops.to_can_async_p = remote_return_zero;
+  remote_ops.to_is_async_p = remote_return_zero;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -7256,14 +7266,14 @@ static int
 remote_can_async_p (void)
 {
   /* We're async whenever the serial device is.  */
-  return (current_target.to_async_mask_value) && serial_can_async_p (remote_desc);
+  return remote_async_mask_value && serial_can_async_p (remote_desc);
 }
 
 static int
 remote_is_async_p (void)
 {
   /* We're async whenever the serial device is.  */
-  return (current_target.to_async_mask_value) && serial_is_async_p (remote_desc);
+  return remote_async_mask_value && serial_is_async_p (remote_desc);
 }
 
 /* Pass the SERIAL event on and up to the client.  One day this code
@@ -7287,7 +7297,7 @@ static void
 remote_async (void (*callback) (enum inferior_event_type event_type,
 				void *context), void *context)
 {
-  if (current_target.to_async_mask_value == 0)
+  if (remote_async_mask_value == 0)
     internal_error (__FILE__, __LINE__,
 		    _("Calling remote_async when async is masked"));
 
@@ -7301,6 +7311,14 @@ remote_async (void (*callback) (enum inf
     serial_async (remote_desc, NULL, NULL);
 }
 
+static int
+remote_async_mask (int new_mask)
+{
+  int curr_mask = remote_async_mask_value;
+  remote_async_mask_value = new_mask;
+  return curr_mask;
+}
+
 /* Target async and target extended-async.
 
    This are temporary targets, until it is all tested.  Eventually
@@ -7360,7 +7378,7 @@ Specify the serial device it is connecte
   remote_async_ops.to_can_async_p = remote_can_async_p;
   remote_async_ops.to_is_async_p = remote_is_async_p;
   remote_async_ops.to_async = remote_async;
-  remote_async_ops.to_async_mask_value = 1;
+  remote_async_ops.to_async_mask = remote_async_mask;
   remote_async_ops.to_magic = OPS_MAGIC;
   remote_async_ops.to_memory_map = remote_memory_map;
   remote_async_ops.to_flash_erase = remote_flash_erase;
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.993
diff -u -p -r1.993 Makefile.in
--- Makefile.in	16 Mar 2008 08:50:43 -0000	1.993
+++ Makefile.in	21 Mar 2008 17:05:54 -0000
@@ -2351,7 +2351,7 @@ linux-nat.o: linux-nat.c $(defs_h) $(inf
 	$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
 	$(gdbcmd_h) $(regcache_h) $(regset_h) $(inf_ptrace_h) $(auxv_h) \
 	$(elf_bfd_h) $(gregset_h) $(gdbcore_h) $(gdbthread_h) $(gdb_stat_h) \
-	$(linux_fork_h)
+	$(linux_fork_h) $(inf_loop_h) $(event_loop_h) $(event_top_h)
 linux-thread-db.o: linux-thread-db.c $(defs_h) $(gdb_assert_h) \
 	$(gdb_proc_service_h) $(gdb_thread_db_h) $(bfd_h) $(exceptions_h) \
 	$(gdbthread_h) $(inferior_h) $(symfile_h) $(objfiles_h) $(target_h) \
Index: doc/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/doc/ChangeLog,v
retrieving revision 1.757
diff -u -p -r1.757 ChangeLog
--- doc/ChangeLog	21 Mar 2008 15:02:37 -0000	1.757
+++ doc/ChangeLog	21 Mar 2008 17:05:55 -0000
@@ -1,3 +1,9 @@
+2008-03-21  Pedro Alves  <pedro@codesourcery.com>
+
+	* gdb.texinfo (Debugging Output): Document
+	"set/show debug lin-lwp-async".
+	(Maintenance Commands): Document "maint set/show linux-async".
+
 2008-03-21  Daniel Jacobowitz  <dan@codesourcery.com>
 
 	* gdb.texinfo (Expressions): Update description of malloced arrays.
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.476
diff -u -p -r1.476 gdb.texinfo
--- doc/gdb.texinfo	21 Mar 2008 15:02:37 -0000	1.476
+++ doc/gdb.texinfo	21 Mar 2008 17:06:01 -0000
@@ -16407,6 +16407,12 @@ Displays the current state of @value{GDB
 Turns on or off debugging messages from the Linux LWP debug support.
 @item show debug lin-lwp
 Show the current state of Linux LWP debugging messages.
+@item set debug lin-lwp-async
+@cindex @sc{gnu}/Linux LWP async debug messages
+@cindex Linux lightweight processes
+Turns on or off debugging messages from the Linux LWP async debug support.
+@item show debug lin-lwp-async
+Show the current state of Linux LWP async debugging messages.
 @item set debug observer
 @cindex observer debugging info
 Turns on or off display of @value{GDBN} observer debugging.  This
@@ -23242,6 +23248,16 @@ data in a @file{gmon.out} file, be sure 
 Configuring with @samp{--enable-profiling} arranges for @value{GDBN} to be
 compiled with the @samp{-pg} compiler option.
 
+@kindex maint set linux-async
+@kindex maint show linux-async
+@cindex asynchronous support
+@item maint set linux-async
+@itemx maint show linux-async
+Control the GNU/Linux native asynchronous support of @value{GDBN}.
+
+GNU/Linux native asynchronous support will be disabled until you use
+the @samp{maint set linux-async} command to enable it.
+
 @kindex maint show-debug-regs
 @cindex x86 hardware debug registers
 @item maint show-debug-regs

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]