* gdbarch.sh: Document the return_value method. Explain that
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index e8cc7c55b575ccf65d6fd78f04647442467ded21..9511815ecd6f478ce87714dda4465d54abe3b06b 100644 (file)
@@ -1,13 +1,13 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "inferior.h"
 
 #include "defs.h"
 #include "inferior.h"
@@ -48,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 "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
 
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
 #define __WALL          0x40000000 /* Wait for any child.  */
 #endif
 
 #define __WALL          0x40000000 /* Wait for any child.  */
 #endif
 
+#ifndef PTRACE_GETSIGINFO
+#define PTRACE_GETSIGINFO    0x4202
+#endif
+
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
+/* The method to call, if any, when a new thread is attached.  */
+static void (*linux_nat_new_thread) (ptid_t);
+
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
 static LONGEST (*super_xfer_partial) (struct target_ops *, 
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
 static LONGEST (*super_xfer_partial) (struct target_ops *, 
@@ -108,6 +116,15 @@ show_debug_linux_nat (struct ui_file *file, int from_tty,
                    value);
 }
 
                    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
 static int linux_parent_pid;
 
 struct simple_pid_list
@@ -128,6 +145,158 @@ static int linux_supports_tracefork_flag = -1;
 
 static int linux_supports_tracevforkdone_flag = -1;
 
 
 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 events 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)
+    ;
+}
+
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -178,12 +347,21 @@ linux_tracefork_child (void)
   _exit (0);
 }
 
   _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;
 
 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);
   do
     {
       ret = waitpid (pid, status, flags);
@@ -357,6 +535,9 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
   int has_vforked;
   int parent_pid, child_pid;
 
   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);
   get_last_target_status (&last_ptid, &last_status);
   has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
   parent_pid = ptid_get_lwp (last_ptid);
@@ -378,7 +559,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       /* Detach new forked process?  */
       if (detach_fork)
        {
       /* Detach new forked process?  */
       if (detach_fork)
        {
-         if (debug_linux_nat)
+         if (info_verbose || debug_linux_nat)
            {
              target_terminal_ours ();
              fprintf_filtered (gdb_stdlog,
            {
              target_terminal_ours ();
              fprintf_filtered (gdb_stdlog,
@@ -463,7 +644,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
-      if (debug_linux_nat)
+      if (info_verbose || debug_linux_nat)
        {
          target_terminal_ours ();
          fprintf_filtered (gdb_stdlog,
        {
          target_terminal_ours ();
          fprintf_filtered (gdb_stdlog,
@@ -501,21 +682,24 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          fork_save_infrun_state (fp, 0);
        }
       else
          fork_save_infrun_state (fp, 0);
        }
       else
-       {
-         target_detach (NULL, 0);
-       }
+       target_detach (NULL, 0);
 
 
-      inferior_ptid = pid_to_ptid (child_pid);
+      inferior_ptid = ptid_build (child_pid, child_pid, 0);
 
       /* Reinstall ourselves, since we might have been removed in
         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
 
       /* Reinstall ourselves, since we might have been removed in
         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
+      linux_nat_switch_fork (inferior_ptid);
+      check_for_thread_db ();
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
     }
 
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
     }
 
+  if (target_can_async_p ())
+    target_async (inferior_event_handler, 0);
+
   return 0;
 }
 
   return 0;
 }
 
@@ -575,17 +759,12 @@ linux_child_insert_exec_catchpoint (int pid)
      because the "zombies" stay around.  */
 
 /* List of known LWPs.  */
      because the "zombies" stay around.  */
 
 /* List of known LWPs.  */
-static struct lwp_info *lwp_list;
+struct lwp_info *lwp_list;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
 \f
 
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
 \f
 
-#define GET_LWP(ptid)          ptid_get_lwp (ptid)
-#define GET_PID(ptid)          ptid_get_pid (ptid)
-#define is_lwp(ptid)           (GET_LWP (ptid) != 0)
-#define BUILD_LWP(lwp, pid)    ptid_build (pid, lwp, 0)
-
 /* If the last reported event was a SIGTRAP, this variable is set to
    the process id of the LWP/thread that got it.  */
 ptid_t trap_ptid;
 /* If the last reported event was a SIGTRAP, this variable is set to
    the process id of the LWP/thread that got it.  */
 ptid_t trap_ptid;
@@ -609,14 +788,19 @@ static sigset_t normal_mask;
    _initialize_linux_nat.  */
 static sigset_t suspend_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;
 \f
 
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
 \f
 
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
+static int cancel_breakpoint (struct lwp_info *lp);
+
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
@@ -659,7 +843,8 @@ init_lwp_list (void)
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
-   structure describing the new LWP.  */
+   structure describing the new LWP.  The LWP should already be stopped
+   (with an exception for the very first LWP).  */
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
@@ -680,6 +865,9 @@ add_lwp (ptid_t ptid)
   lwp_list = lp;
   ++num_lwps;
 
   lwp_list = lp;
   ++num_lwps;
 
+  if (num_lwps > 1 && linux_nat_new_thread != NULL)
+    linux_nat_new_thread (ptid);
+
   return lp;
 }
 
   return lp;
 }
 
@@ -802,20 +990,6 @@ prune_lwps (void)
       p = &(*p)->next;
 }
 
       p = &(*p)->next;
 }
 
-/* Callback for iterate_over_threads that finds a thread corresponding
-   to the given LWP.  */
-
-static int
-find_thread_from_lwp (struct thread_info *thr, void *dummy)
-{
-  ptid_t *ptid_p = dummy;
-
-  if (GET_LWP (thr->ptid) && GET_LWP (thr->ptid) == GET_LWP (*ptid_p))
-    return 1;
-  else
-    return 0;
-}
-
 /* Handle the exit of a single thread LP.  */
 
 static void
 /* Handle the exit of a single thread LP.  */
 
 static void
@@ -823,32 +997,14 @@ exit_lwp (struct lwp_info *lp)
 {
   if (in_thread_list (lp->ptid))
     {
 {
   if (in_thread_list (lp->ptid))
     {
+      if (print_thread_events)
+       printf_unfiltered (_("[%s exited]\n"), target_pid_to_str (lp->ptid));
+
       /* Core GDB cannot deal with us deleting the current thread.  */
       if (!ptid_equal (lp->ptid, inferior_ptid))
        delete_thread (lp->ptid);
       else
        record_dead_thread (lp->ptid);
       /* Core GDB cannot deal with us deleting the current thread.  */
       if (!ptid_equal (lp->ptid, inferior_ptid))
        delete_thread (lp->ptid);
       else
        record_dead_thread (lp->ptid);
-      printf_unfiltered (_("[%s exited]\n"),
-                        target_pid_to_str (lp->ptid));
-    }
-  else
-    {
-      /* Even if LP->PTID is not in the global GDB thread list, the
-        LWP may be - with an additional thread ID.  We don't need
-        to print anything in this case; thread_db is in use and
-        already took care of that.  But it didn't delete the thread
-        in order to handle zombies correctly.  */
-
-      struct thread_info *thr;
-
-      thr = iterate_over_threads (find_thread_from_lwp, &lp->ptid);
-      if (thr)
-       {
-         if (!ptid_equal (thr->ptid, inferior_ptid))
-           delete_thread (thr->ptid);
-         else
-           record_dead_thread (thr->ptid);
-       }
     }
 
   delete_lwp (lp->ptid);
     }
 
   delete_lwp (lp->ptid);
@@ -860,19 +1016,15 @@ exit_lwp (struct lwp_info *lp)
    be attached.  */
 
 int
    be attached.  */
 
 int
-lin_lwp_attach_lwp (ptid_t ptid, int verbose)
+lin_lwp_attach_lwp (ptid_t ptid)
 {
   struct lwp_info *lp;
 {
   struct lwp_info *lp;
+  int async_events_were_enabled = 0;
 
   gdb_assert (is_lwp (ptid));
 
 
   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);
 
 
   lp = find_lwp_pid (ptid);
 
@@ -886,12 +1038,13 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
     {
       pid_t pid;
       int status;
     {
       pid_t pid;
       int status;
+      int cloned = 0;
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
        {
          /* If we fail to attach to the thread, issue a warning,
             but continue.  One way this can happen is if thread
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
        {
          /* If we fail to attach to the thread, issue a warning,
             but continue.  One way this can happen is if thread
-            creation is interrupted; as of Linux 2.6.19, a kernel
+            creation is interrupted; as of Linux kernel 2.6.19, a
             bug may place threads in the thread list and then fail
             to create them.  */
          warning (_("Can't attach %s: %s"), target_pid_to_str (ptid),
             bug may place threads in the thread list and then fail
             to create them.  */
          warning (_("Can't attach %s: %s"), target_pid_to_str (ptid),
@@ -899,9 +1052,6 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
          return -1;
        }
 
          return -1;
        }
 
-      if (lp == NULL)
-       lp = add_lwp (ptid);
-
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
@@ -912,12 +1062,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
        {
          /* Try again with __WCLONE to check cloned processes.  */
          pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
        {
          /* Try again with __WCLONE to check cloned processes.  */
          pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
-         lp->cloned = 1;
+         cloned = 1;
        }
 
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
        }
 
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
+      if (lp == NULL)
+       lp = add_lwp (ptid);
+      lp->cloned = cloned;
+
       target_post_attach (pid);
 
       lp->stopped = 1;
       target_post_attach (pid);
 
       lp->stopped = 1;
@@ -943,52 +1097,105 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
       lp->stopped = 1;
     }
 
       lp->stopped = 1;
     }
 
-  if (verbose)
-    printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
+  if (async_events_were_enabled)
+    linux_nat_async_events (1);
 
   return 0;
 }
 
 
   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;
   pid_t pid;
   int status;
 static void
 linux_nat_attach (char *args, int from_tty)
 {
   struct lwp_info *lp;
   pid_t pid;
   int status;
+  int cloned = 0;
+  int options = 0;
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
-  /* Add the initial process as the first LWP to the list.  */
-  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
-  lp = add_lwp (inferior_ptid);
+  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.  */
 
   /* 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.  */
-  pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
+  pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
   if (pid == -1 && errno == ECHILD)
     {
       warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
   if (pid == -1 && errno == ECHILD)
     {
       warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
-      pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
-      lp->cloned = 1;
+      options = __WCLONE;
+      pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
+      cloned = 1;
     }
 
   gdb_assert (pid == GET_PID (inferior_ptid)
              && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
 
     }
 
   gdb_assert (pid == GET_PID (inferior_ptid)
              && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
 
-  lp->stopped = 1;
+  /* Add the initial process as the first LWP to the list.  */
+  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  lp = add_lwp (inferior_ptid);
+  lp->cloned = cloned;
 
 
-  /* Fake the SIGSTOP that core GDB expects.  */
-  lp->status = W_STOPCODE (SIGSTOP);
+  /* If this process is not using thread_db, then we still don't
+     detect any other threads, but add at least this one.  */
+  add_thread_silent (lp->ptid);
+
+  lp->stopped = 1;
   lp->resumed = 1;
   lp->resumed = 1;
-  if (debug_linux_nat)
+
+  if (!target_can_async_p ())
     {
     {
-      fprintf_unfiltered (gdb_stdlog,
-                         "LLA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+      /* Fake the SIGSTOP that core GDB expects.  */
+      lp->status = W_STOPCODE (SIGSTOP);
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
+    }
+  else
+    {
+      /* We already waited for this LWP, so put the wait result on the
+        pipe.  The event loop will wake up and gets us to handling
+        this event.  */
+      linux_nat_event_pipe_push (pid, status, options);
+      /* Register in the event loop.  */
+      target_async (inferior_event_handler, 0);
     }
 }
 
     }
 }
 
@@ -1045,6 +1252,7 @@ detach_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid),
                            strsignal (WSTOPSIG (lp->status)));
 
                            target_pid_to_str (lp->ptid),
                            strsignal (WSTOPSIG (lp->status)));
 
+      drain_queued_events (GET_LWP (lp->ptid));
       delete_lwp (lp->ptid);
     }
 
       delete_lwp (lp->ptid);
     }
 
@@ -1054,6 +1262,10 @@ detach_callback (struct lwp_info *lp, void *data)
 static void
 linux_nat_detach (char *args, int from_tty)
 {
 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.  */
   iterate_over_lwps (detach_callback, NULL);
 
   /* Only the initial process should be left right now.  */
@@ -1064,12 +1276,12 @@ linux_nat_detach (char *args, int from_tty)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
   /* 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);
   linux_ops->to_detach (args, from_tty);
+
+  if (target_can_async_p ())
+    drain_queued_events (pid);
 }
 
 /* Resume LP.  */
 }
 
 /* Resume LP.  */
@@ -1079,8 +1291,6 @@ resume_callback (struct lwp_info *lp, void *data)
 {
   if (lp->stopped && lp->status == 0)
     {
 {
   if (lp->stopped && lp->status == 0)
     {
-      struct thread_info *tp;
-
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -1089,6 +1299,7 @@ resume_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
                            target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
+      memset (&lp->siginfo, 0, sizeof (lp->siginfo));
     }
 
   return 0;
     }
 
   return 0;
@@ -1124,6 +1335,10 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
 
   prune_lwps ();
 
 
   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);
 
   /* A specific PTID means `step only this process id'.  */
   resume_all = (PIDGET (ptid) == -1);
 
@@ -1138,74 +1353,85 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
     ptid = inferior_ptid;
 
   lp = find_lwp_pid (ptid);
     ptid = inferior_ptid;
 
   lp = find_lwp_pid (ptid);
-  if (lp)
-    {
-      ptid = pid_to_ptid (GET_LWP (lp->ptid));
+  gdb_assert (lp != NULL);
 
 
-      /* Remember if we're stepping.  */
-      lp->step = step;
+  ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
 
-      /* Mark this LWP as resumed.  */
-      lp->resumed = 1;
+  /* Remember if we're stepping.  */
+  lp->step = step;
 
 
-      /* If we have a pending wait status for this thread, there is no
-        point in resuming the process.  But first make sure that
-        linux_nat_wait won't preemptively handle the event - we
-        should never take this short-circuit if we are going to
-        leave LP running, since we have skipped resuming all the
-        other threads.  This bit of code needs to be synchronized
-        with linux_nat_wait.  */
+  /* Mark this LWP as resumed.  */
+  lp->resumed = 1;
 
 
-      if (lp->status && WIFSTOPPED (lp->status))
-       {
-         int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+  /* If we have a pending wait status for this thread, there is no
+     point in resuming the process.  But first make sure that
+     linux_nat_wait won't preemptively handle the event - we
+     should never take this short-circuit if we are going to
+     leave LP running, since we have skipped resuming all the
+     other threads.  This bit of code needs to be synchronized
+     with linux_nat_wait.  */
 
 
-         if (signal_stop_state (saved_signo) == 0
-             && signal_print_state (saved_signo) == 0
-             && signal_pass_state (saved_signo) == 1)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLR: Not short circuiting for ignored "
-                                   "status 0x%x\n", lp->status);
-
-             /* FIXME: What should we do if we are supposed to continue
-                this thread with a signal?  */
-             gdb_assert (signo == TARGET_SIGNAL_0);
-             signo = saved_signo;
-             lp->status = 0;
-           }
-       }
+  /* In async mode, we never have pending wait status.  */
+  if (target_can_async_p () && lp->status)
+    internal_error (__FILE__, __LINE__, "Pending status in async mode");
+
+  if (lp->status && WIFSTOPPED (lp->status))
+    {
+      int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
 
 
-      if (lp->status)
+      if (signal_stop_state (saved_signo) == 0
+         && signal_print_state (saved_signo) == 0
+         && signal_pass_state (saved_signo) == 1)
        {
        {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LLR: Not short circuiting for ignored "
+                               "status 0x%x\n", lp->status);
+
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
+         signo = saved_signo;
+         lp->status = 0;
+       }
+    }
 
 
-         if (debug_linux_nat)
-           fprintf_unfiltered (gdb_stdlog,
-                               "LLR: Short circuiting for status 0x%x\n",
-                               lp->status);
+  if (lp->status)
+    {
+      /* FIXME: What should we do if we are supposed to continue
+        this thread with a signal?  */
+      gdb_assert (signo == TARGET_SIGNAL_0);
 
 
-         return;
-       }
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLR: Short circuiting for status 0x%x\n",
+                           lp->status);
 
 
-      /* Mark LWP as not stopped to prevent it from being continued by
-         resume_callback.  */
-      lp->stopped = 0;
+      return;
     }
 
     }
 
+  /* Mark LWP as not stopped to prevent it from being continued by
+     resume_callback.  */
+  lp->stopped = 0;
+
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
   linux_ops->to_resume (ptid, step, signo);
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
   linux_ops->to_resume (ptid, step, signo);
+  memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
                        step ? "PTRACE_SINGLESTEP" : "PTRACE_CONT",
                        target_pid_to_str (ptid),
                        signo ? strsignal (signo) : "0");
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
                        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.  */
 }
 
 /* Issue kill to specified lwp.  */
@@ -1418,6 +1644,22 @@ wait_lwp (struct lwp_info *lp)
   return status;
 }
 
   return status;
 }
 
+/* Save the most recent siginfo for LP.  This is currently only called
+   for SIGTRAP; some ports use the si_addr field for
+   target_stopped_data_address.  In the future, it may also be used to
+   restore the siginfo of requeued signals.  */
+
+static void
+save_siginfo (struct lwp_info *lp)
+{
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
+         (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
+
+  if (errno != 0)
+    memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+}
+
 /* Send a SIGSTOP to LP.  */
 
 static int
 /* Send a SIGSTOP to LP.  */
 
 static int
@@ -1503,6 +1745,9 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                 user will delete or disable the breakpoint, but the
                 thread will have already tripped on it.  */
 
                 user will delete or disable the breakpoint, but the
                 thread will have already tripped on it.  */
 
+             /* Save the trap's siginfo in case we need it later.  */
+             save_siginfo (lp);
+
              /* Now resume this LWP and get the SIGSTOP event. */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
              /* Now resume this LWP and get the SIGSTOP event. */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -1517,22 +1762,44 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                                      "SWC: Candidate SIGTRAP event in %s\n",
                                      target_pid_to_str (lp->ptid));
                }
                                      "SWC: Candidate SIGTRAP event in %s\n",
                                      target_pid_to_str (lp->ptid));
                }
-             /* Hold the SIGTRAP for handling by linux_nat_wait. */
+             /* Hold this event/waitstatus while we check to see if
+                there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, data);
              stop_wait_callback (lp, data);
-             /* If there's another event, throw it back into the queue. */
-             if (lp->status)
+
+             if (target_can_async_p ())
                {
                {
-                 if (debug_linux_nat)
+                 /* Don't leave a pending wait status in async mode.
+                    Retrigger the breakpoint.  */
+                 if (!cancel_breakpoint (lp))
                    {
                    {
-                     fprintf_unfiltered (gdb_stdlog,
-                                         "SWC: kill %s, %s\n",
-                                         target_pid_to_str (lp->ptid),
-                                         status_to_str ((int) status));
+                     /* There was no gdb breakpoint set at pc.  Put
+                        the event back in the queue.  */
+                     if (debug_linux_nat)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "SWC: kill %s, %s\n",
+                                           target_pid_to_str (lp->ptid),
+                                           status_to_str ((int) status));
+                     kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+                   }
+               }
+             else
+               {
+                 /* Hold the SIGTRAP for handling by
+                    linux_nat_wait. */
+                 /* If there's another event, throw it back into the
+                    queue. */
+                 if (lp->status)
+                   {
+                     if (debug_linux_nat)
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "SWC: kill %s, %s\n",
+                                           target_pid_to_str (lp->ptid),
+                                           status_to_str ((int) status));
+                     kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
                    }
                    }
-                 kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
+                 /* Save the sigtrap event. */
+                 lp->status = status;
                }
                }
-             /* Save the sigtrap event. */
-             lp->status = status;
              return 0;
            }
          else
              return 0;
            }
          else
@@ -1559,12 +1826,11 @@ stop_wait_callback (struct lwp_info *lp, void *data)
              /* Hold this event/waitstatus while we check to see if
                 there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, data);
              /* Hold this event/waitstatus while we check to see if
                 there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, data);
-             /* If the lp->status field is still empty, use it to hold
-                this event.  If not, then this event must be returned
-                to the event queue of the LWP.  */
-             if (lp->status == 0)
-               lp->status = status;
-             else
+
+             /* If the lp->status field is still empty, use it to
+                hold this event.  If not, then this event must be
+                returned to the event queue of the LWP.  */
+             if (lp->status || target_can_async_p ())
                {
                  if (debug_linux_nat)
                    {
                {
                  if (debug_linux_nat)
                    {
@@ -1575,6 +1841,8 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                    }
                  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
                }
                    }
                  kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
                }
+             else
+               lp->status = status;
              return 0;
            }
        }
              return 0;
            }
        }
@@ -1744,6 +2012,37 @@ select_event_lwp_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
   return 0;
 }
 
+static int
+cancel_breakpoint (struct lwp_info *lp)
+{
+  /* Arrange for a breakpoint to be hit again later.  We don't keep
+     the SIGTRAP status and don't forward the SIGTRAP signal to the
+     LWP.  We will handle the current event, eventually we will resume
+     this LWP, and this breakpoint will trap again.
+
+     If we do not do this, then we run the risk that the user will
+     delete or disable the breakpoint, but the LWP will have already
+     tripped on it.  */
+
+  if (breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
+                                 gdbarch_decr_pc_after_break
+                                 (current_gdbarch)))
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "CB: Push back breakpoint for %s\n",
+                           target_pid_to_str (lp->ptid));
+
+      /* Back up the PC if necessary.  */
+      if (gdbarch_decr_pc_after_break (current_gdbarch))
+       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
+                     (current_gdbarch),
+                     lp->ptid);
+      return 1;
+    }
+  return 0;
+}
+
 static int
 cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 {
 static int
 cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 {
@@ -1766,24 +2065,9 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
 
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
-      && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
-                                    gdbarch_decr_pc_after_break
-                                      (current_gdbarch)))
-    {
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "CBC: Push back breakpoint for %s\n",
-                           target_pid_to_str (lp->ptid));
-
-      /* Back up the PC if necessary.  */
-      if (gdbarch_decr_pc_after_break (current_gdbarch))
-       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
-                                                (current_gdbarch),
-                     lp->ptid);
-
-      /* Throw away the SIGTRAP.  */
-      lp->status = 0;
-    }
+      && cancel_breakpoint (lp))
+    /* Throw away the SIGTRAP.  */
+    lp->status = 0;
 
   return 0;
 }
 
   return 0;
 }
@@ -1871,49 +2155,268 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
   return 0;
 }
 
-static ptid_t
-linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+/* Check if we should go on and pass this event to common code.
+   Return the affected lwp if we are, or NULL otherwise.  */
+static struct lwp_info *
+linux_nat_filter_event (int lwpid, int status, int options)
 {
 {
-  struct lwp_info *lp = NULL;
-  int options = 0;
-  int status = 0;
-  pid_t pid = PIDGET (ptid);
-  sigset_t flush_mask;
-
-  /* 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.  */
-  if (num_lwps == 0)
-    {
-      gdb_assert (!is_lwp (inferior_ptid));
+  struct lwp_info *lp;
 
 
-      inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
-                                GET_PID (inferior_ptid));
-      lp = add_lwp (inferior_ptid);
-      lp->resumed = 1;
-    }
+  lp = find_lwp_pid (pid_to_ptid (lwpid));
 
 
-  sigemptyset (&flush_mask);
+  /* Check for stop events reported by a process we didn't already
+     know about - anything not already in our LWP list.
 
 
-  /* Make sure SIGCHLD is blocked.  */
-  if (!sigismember (&blocked_mask, SIGCHLD))
+     If we're expecting to receive stopped processes after
+     fork, vfork, and clone events, then we'll just add the
+     new one to our list and go back to waiting for the event
+     to be reported - the stopped process might be returned
+     from waitpid before or after the event is.  */
+  if (WIFSTOPPED (status) && !lp)
     {
     {
-      sigaddset (&blocked_mask, SIGCHLD);
-      sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
+      linux_record_stopped_pid (lwpid, status);
+      return NULL;
     }
 
     }
 
-retry:
+  /* Make sure we don't report an event for the exit of an LWP not in
+     our list, i.e.  not part of the current process.  This can happen
+     if we detach from a program we original forked and then it
+     exits.  */
+  if (!WIFSTOPPED (status) && !lp)
+    return NULL;
+
+  /* NOTE drow/2003-06-17: This code seems to be meant for debugging
+     CLONE_PTRACE processes which do not use the thread library -
+     otherwise we wouldn't find the new LWP this way.  That doesn't
+     currently work, and the following code is currently unreachable
+     due to the two blocks above.  If it's fixed some day, this code
+     should be broken out into a function so that we can also pick up
+     LWPs from the new interface.  */
+  if (!lp)
+    {
+      lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid)));
+      if (options & __WCLONE)
+       lp->cloned = 1;
 
 
-  /* Make sure there is at least one LWP that has been resumed.  */
-  gdb_assert (iterate_over_lwps (resumed_callback, NULL));
+      gdb_assert (WIFSTOPPED (status)
+                 && WSTOPSIG (status) == SIGSTOP);
+      lp->signalled = 1;
 
 
-  /* First check if there is a LWP with a wait status pending.  */
-  if (pid == -1)
-    {
+      if (!in_thread_list (inferior_ptid))
+       {
+         inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+                                    GET_PID (inferior_ptid));
+         add_thread (inferior_ptid);
+       }
+
+      add_thread (lp->ptid);
+    }
+
+  /* Save the trap's siginfo in case we need it later.  */
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+    save_siginfo (lp);
+
+  /* Handle GNU/Linux's extended waitstatus for trace events.  */
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: Handling extended status 0x%06x\n",
+                           status);
+      if (linux_handle_extended_wait (lp, status, 0))
+       return NULL;
+    }
+
+  /* Check if the thread has exited.  */
+  if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
+    {
+      /* If this is the main thread, we must stop all threads and
+        verify if they are still alive.  This is because in the nptl
+        thread model, there is no signal issued for exiting LWPs
+        other than the main thread.  We only get the main thread exit
+        signal once all child threads have already exited.  If we
+        stop all the threads and use the stop_wait_callback to check
+        if they have exited we can determine whether this signal
+        should be ignored or whether it means the end of the debugged
+        application, regardless of which threading model is being
+        used.  */
+      if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
+       {
+         lp->stopped = 1;
+         iterate_over_lwps (stop_and_resume_callback, NULL);
+       }
+
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s exited.\n",
+                           target_pid_to_str (lp->ptid));
+
+      exit_lwp (lp);
+
+      /* If there is at least one more LWP, then the exit signal was
+        not the end of the debugged application and should be
+        ignored.  */
+      if (num_lwps > 0)
+       {
+         /* Make sure there is at least one thread running.  */
+         gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+         /* Discard the event.  */
+         return NULL;
+       }
+    }
+
+  /* Check if the current LWP has previously exited.  In the nptl
+     thread model, LWPs other than the main thread do not issue
+     signals when they exit so we must check whenever the thread has
+     stopped.  A similar check is made in stop_wait_callback().  */
+  if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid))
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s exited.\n",
+                           target_pid_to_str (lp->ptid));
+
+      exit_lwp (lp);
+
+      /* Make sure there is at least one thread running.  */
+      gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+      /* Discard the event.  */
+      return NULL;
+    }
+
+  /* Make sure we don't report a SIGSTOP that we sent ourselves in
+     an attempt to stop an LWP.  */
+  if (lp->signalled
+      && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: Delayed SIGSTOP caught for %s.\n",
+                           target_pid_to_str (lp->ptid));
+
+      /* This is a delayed SIGSTOP.  */
+      lp->signalled = 0;
+
+      registers_changed ();
+
+      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                           lp->step, TARGET_SIGNAL_0);
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
+                           lp->step ?
+                           "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+                           target_pid_to_str (lp->ptid));
+
+      lp->stopped = 0;
+      gdb_assert (lp->resumed);
+
+      /* Discard the event.  */
+      return NULL;
+    }
+
+  /* An interesting event.  */
+  gdb_assert (lp);
+  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);
+      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)
+{
+  struct lwp_info *lp = NULL;
+  int options = 0;
+  int status = 0;
+  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.  */
+  if (num_lwps == 0)
+    {
+      gdb_assert (!is_lwp (inferior_ptid));
+
+      inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+                                GET_PID (inferior_ptid));
+      lp = add_lwp (inferior_ptid);
+      lp->resumed = 1;
+      /* Add the main thread to GDB's thread list.  */
+      add_thread_silent (lp->ptid);
+    }
+
+  sigemptyset (&flush_mask);
+
+  if (target_can_async_p ())
+    /* Block events while we're here.  */
+    target_async (NULL, 0);
+
+retry:
+
+  /* Make sure there is at least one LWP that has been resumed.  */
+  gdb_assert (iterate_over_lwps (resumed_callback, NULL));
+
+  /* First check if there is a LWP with a wait status pending.  */
+  if (pid == -1)
+    {
       /* Any LWP that's been resumed will do.  */
       lp = iterate_over_lwps (status_callback, NULL);
       if (lp)
        {
       /* Any LWP that's been resumed will do.  */
       lp = iterate_over_lwps (status_callback, NULL);
       if (lp)
        {
+         if (target_can_async_p ())
+           internal_error (__FILE__, __LINE__,
+                           "Found an LWP with a pending status in async mode.");
+
          status = lp->status;
          lp->status = 0;
 
          status = lp->status;
          lp->status = 0;
 
@@ -1924,7 +2427,7 @@ retry:
                                target_pid_to_str (lp->ptid));
        }
 
                                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;
          cloned and uncloned processes.  We start with the cloned
          processes.  */
       options = __WCLONE | WNOHANG;
@@ -1983,15 +2486,24 @@ retry:
       stop_wait_callback (lp, NULL);
     }
 
       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;
 
 
   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);
       if (lwpid > 0)
        {
          gdb_assert (pid == -1 || lwpid == pid);
@@ -2003,165 +2515,10 @@ retry:
                                  (long) lwpid, status_to_str (status));
            }
 
                                  (long) lwpid, status_to_str (status));
            }
 
-         lp = find_lwp_pid (pid_to_ptid (lwpid));
-
-         /* Check for stop events reported by a process we didn't
-            already know about - anything not already in our LWP
-            list.
-
-            If we're expecting to receive stopped processes after
-            fork, vfork, and clone events, then we'll just add the
-            new one to our list and go back to waiting for the event
-            to be reported - the stopped process might be returned
-            from waitpid before or after the event is.  */
-         if (WIFSTOPPED (status) && !lp)
-           {
-             linux_record_stopped_pid (lwpid, status);
-             status = 0;
-             continue;
-           }
-
-         /* Make sure we don't report an event for the exit of an LWP not in
-            our list, i.e.  not part of the current process.  This can happen
-            if we detach from a program we original forked and then it
-            exits.  */
-         if (!WIFSTOPPED (status) && !lp)
-           {
-             status = 0;
-             continue;
-           }
-
-         /* NOTE drow/2003-06-17: This code seems to be meant for debugging
-            CLONE_PTRACE processes which do not use the thread library -
-            otherwise we wouldn't find the new LWP this way.  That doesn't
-            currently work, and the following code is currently unreachable
-            due to the two blocks above.  If it's fixed some day, this code
-            should be broken out into a function so that we can also pick up
-            LWPs from the new interface.  */
+         lp = linux_nat_filter_event (lwpid, status, options);
          if (!lp)
            {
          if (!lp)
            {
-             lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid)));
-             if (options & __WCLONE)
-               lp->cloned = 1;
-
-             gdb_assert (WIFSTOPPED (status)
-                         && WSTOPSIG (status) == SIGSTOP);
-             lp->signalled = 1;
-
-             if (!in_thread_list (inferior_ptid))
-               {
-                 inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
-                                            GET_PID (inferior_ptid));
-                 add_thread (inferior_ptid);
-               }
-
-             add_thread (lp->ptid);
-             printf_unfiltered (_("[New %s]\n"),
-                                target_pid_to_str (lp->ptid));
-           }
-
-         /* Handle GNU/Linux's extended waitstatus for trace events.  */
-         if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: Handling extended status 0x%06x\n",
-                                   status);
-             if (linux_handle_extended_wait (lp, status, 0))
-               {
-                 status = 0;
-                 continue;
-               }
-           }
-
-         /* Check if the thread has exited.  */
-         if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
-           {
-             /* If this is the main thread, we must stop all threads and
-                verify if they are still alive.  This is because in the nptl
-                thread model, there is no signal issued for exiting LWPs
-                other than the main thread.  We only get the main thread
-                exit signal once all child threads have already exited.
-                If we stop all the threads and use the stop_wait_callback
-                to check if they have exited we can determine whether this
-                signal should be ignored or whether it means the end of the
-                debugged application, regardless of which threading model
-                is being used.  */
-             if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
-               {
-                 lp->stopped = 1;
-                 iterate_over_lwps (stop_and_resume_callback, NULL);
-               }
-
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s exited.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             exit_lwp (lp);
-
-             /* If there is at least one more LWP, then the exit signal
-                was not the end of the debugged application and should be
-                ignored.  */
-             if (num_lwps > 0)
-               {
-                 /* Make sure there is at least one thread running.  */
-                 gdb_assert (iterate_over_lwps (running_callback, NULL));
-
-                 /* Discard the event.  */
-                 status = 0;
-                 continue;
-               }
-           }
-
-         /* Check if the current LWP has previously exited.  In the nptl
-            thread model, LWPs other than the main thread do not issue
-            signals when they exit so we must check whenever the thread
-            has stopped.  A similar check is made in stop_wait_callback().  */
-         if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid))
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s exited.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             exit_lwp (lp);
-
-             /* Make sure there is at least one thread running.  */
-             gdb_assert (iterate_over_lwps (running_callback, NULL));
-
-             /* Discard the event.  */
-             status = 0;
-             continue;
-           }
-
-         /* Make sure we don't report a SIGSTOP that we sent
-            ourselves in an attempt to stop an LWP.  */
-         if (lp->signalled
-             && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: Delayed SIGSTOP caught for %s.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             /* This is a delayed SIGSTOP.  */
-             lp->signalled = 0;
-
-             registers_changed ();
-             linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
-                                   lp->step, TARGET_SIGNAL_0);
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
-                                   lp->step ?
-                                   "PTRACE_SINGLESTEP" : "PTRACE_CONT",
-                                   target_pid_to_str (lp->ptid));
-
-             lp->stopped = 0;
-             gdb_assert (lp->resumed);
-
-             /* Discard the event.  */
+             /* A discarded event.  */
              status = 0;
              continue;
            }
              status = 0;
              continue;
            }
@@ -2174,17 +2531,38 @@ retry:
          /* Alternate between checking cloned and uncloned processes.  */
          options ^= __WCLONE;
 
          /* 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)
          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);
     }
 
        }
 
       /* 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);
 
 
   gdb_assert (lp);
 
@@ -2281,6 +2659,13 @@ retry:
   else
     store_waitstatus (ourstatus, status);
 
   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;
 }
 
   return lp->ptid;
 }
 
@@ -2315,11 +2700,18 @@ kill_wait_callback (struct lwp_info *lp, void *data)
       do
        {
          pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
       do
        {
          pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
-         if (pid != (pid_t) -1 && debug_linux_nat)
+         if (pid != (pid_t) -1)
            {
            {
-             fprintf_unfiltered (gdb_stdlog,
-                                 "KWC: wait %s received unknown.\n",
-                                 target_pid_to_str (lp->ptid));
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "KWC: wait %s received unknown.\n",
+                                   target_pid_to_str (lp->ptid));
+             /* The Linux kernel sometimes fails to kill a thread
+                completely after PTRACE_KILL; that goes from the stop
+                point in do_fork out to the one in
+                get_signal_to_deliever and waits again.  So kill it
+                again.  */
+             kill_callback (lp, NULL);
            }
        }
       while (pid == GET_LWP (lp->ptid));
            }
        }
       while (pid == GET_LWP (lp->ptid));
@@ -2330,11 +2722,14 @@ kill_wait_callback (struct lwp_info *lp, void *data)
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
-      if (pid != (pid_t) -1 && debug_linux_nat)
+      if (pid != (pid_t) -1)
        {
        {
-         fprintf_unfiltered (gdb_stdlog,
-                             "KWC: wait %s received unk.\n",
-                             target_pid_to_str (lp->ptid));
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "KWC: wait %s received unk.\n",
+                               target_pid_to_str (lp->ptid));
+         /* See the call to kill_callback above.  */
+         kill_callback (lp, NULL);
        }
     }
   while (pid == GET_LWP (lp->ptid));
        }
     }
   while (pid == GET_LWP (lp->ptid));
@@ -2350,6 +2745,9 @@ linux_nat_kill (void)
   ptid_t last_ptid;
   int status;
 
   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.  */
   /* 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.  */
@@ -2364,7 +2762,10 @@ linux_nat_kill (void)
     }
 
   if (forks_exist_p ())
     }
 
   if (forks_exist_p ())
-    linux_fork_killall ();
+    {
+      linux_fork_killall ();
+      drain_queued_events (-1);
+    }
   else
     {
       /* Kill all LWP's ...  */
   else
     {
       /* Kill all LWP's ...  */
@@ -2385,13 +2786,13 @@ linux_nat_mourn_inferior (void)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
   /* 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 ())
   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
   else
     /* Multi-fork case.  The current inferior_ptid has exited, but
        there are other viable forks to debug.  Delete the exiting
@@ -2459,6 +2860,13 @@ linux_nat_pid_to_str (ptid_t ptid)
 static void
 sigchld_handler (int signo)
 {
 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.  */
   /* 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.  */
@@ -2688,7 +3096,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_fname).  */
   char fname[16] = { '\0' };
   char fname[16] = { '\0' };
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs).  */
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
@@ -2701,9 +3111,18 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
-         strncat (psargs, " ", sizeof (psargs) - strlen (psargs));
-         strncat (psargs, get_inferior_args (),
-                  sizeof (psargs) - strlen (psargs));
+         char *string_end;
+         char *psargs_end = psargs + sizeof (psargs);
+
+         /* linux_elfcore_write_prpsinfo () handles zero unterminated
+            strings fine.  */
+         string_end = memchr (psargs, 0, sizeof (psargs));
+         if (string_end != NULL)
+           {
+             *string_end++ = ' ';
+             strncpy (string_end, get_inferior_args (),
+                      psargs_end - string_end);
+           }
        }
       note_data = (char *) elfcore_write_prpsinfo (obfd,
                                                   note_data,
        }
       note_data = (char *) elfcore_write_prpsinfo (obfd,
                                                   note_data,
@@ -2926,10 +3345,11 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
        {
          int itmp;
          char ctmp;
        {
          int itmp;
          char ctmp;
+         long ltmp;
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
-         if (fscanf (procfile, "%s ", &buffer[0]) > 0)
+         if (fscanf (procfile, "(%[^)]) ", &buffer[0]) > 0)
            printf_filtered (_("Exec file: %s\n"), buffer);
          if (fscanf (procfile, "%c ", &ctmp) > 0)
            printf_filtered (_("State: %c\n"), ctmp);
            printf_filtered (_("Exec file: %s\n"), buffer);
          if (fscanf (procfile, "%c ", &ctmp) > 0)
            printf_filtered (_("State: %c\n"), ctmp);
@@ -2943,71 +3363,71 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
            printf_filtered (_("TTY: %d\n"), itmp);
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("TTY owner process group: %d\n"), itmp);
            printf_filtered (_("TTY: %d\n"), itmp);
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("TTY owner process group: %d\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Flags: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults (no memory page): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults (memory page faults): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("jiffies remaining in current time slice: %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("'nice' value: %d\n", itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("jiffies until next timeout: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("jiffies until next SIGALRM: %u\n",
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("start time (jiffies since system boot): %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Virtual memory size: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Resident set size: %u\n"), (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("rlim: %u\n", (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("End of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of stack: 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Flags: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults (no memory page): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults (memory page faults): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("jiffies remaining in current time slice: %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("'nice' value: %ld\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next timeout: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next SIGALRM: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("start time (jiffies since system boot): %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Virtual memory size: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Resident set size: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("End of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of stack: 0x%lx\n"), ltmp);
 #if 0                          /* Don't know how architecture-dependent the rest is...
                                   Anyway the signal bitmap info is available from "status".  */
 #if 0                          /* Don't know how architecture-dependent the rest is...
                                   Anyway the signal bitmap info is available from "status".  */
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel stack pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel instr pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Pending signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Blocked signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Ignored signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Catched signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("wchan (system call): 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Blocked signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
          fclose (procfile);
        }
 #endif
          fclose (procfile);
        }
@@ -3163,7 +3583,7 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
                             offset, len);
 }
 
                             offset, len);
 }
 
-/* Create a prototype generic Linux target.  The client can override
+/* Create a prototype generic GNU/Linux target.  The client can override
    it with local methods.  */
 
 static void
    it with local methods.  */
 
 static void
@@ -3205,6 +3625,376 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int))
   return t;
 }
 
   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)
 {
 void
 linux_nat_add_target (struct target_ops *t)
 {
@@ -3216,6 +4006,7 @@ linux_nat_add_target (struct target_ops *t)
   linux_ops = &linux_ops_saved;
 
   /* Override some methods for multithreading.  */
   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;
   t->to_attach = linux_nat_attach;
   t->to_detach = linux_nat_detach;
   t->to_resume = linux_nat_resume;
@@ -3227,6 +4018,13 @@ linux_nat_add_target (struct target_ops *t)
   t->to_pid_to_str = linux_nat_pid_to_str;
   t->to_has_thread_control = tc_schedlock;
 
   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
   /* 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
@@ -3240,10 +4038,31 @@ linux_nat_add_target (struct target_ops *t)
   thread_db_init (t);
 }
 
   thread_db_init (t);
 }
 
+/* Register a method to call whenever a new thread is attached.  */
+void
+linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+{
+  /* Save the pointer.  We only support a single registered instance
+     of the GNU/Linux native target, so we do not need to map this to
+     T.  */
+  linux_nat_new_thread = new_thread;
+}
+
+/* Return the saved siginfo associated with PTID.  */
+struct siginfo *
+linux_nat_get_siginfo (ptid_t ptid)
+{
+  struct lwp_info *lp = find_lwp_pid (ptid);
+
+  gdb_assert (lp != NULL);
+
+  return &lp->siginfo;
+}
+
 void
 _initialize_linux_nat (void)
 {
 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\
 
   add_info ("proc", linux_nat_info_proc_cmd, _("\
 Show /proc process information about any running process.\n\
@@ -3254,27 +4073,63 @@ Specify any of the following keywords for detailed info:\n\
   status   -- list a different bunch of random process info.\n\
   all      -- list all available /proc info."));
 
   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);
 
   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);
 
 
   /* 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);
 }
 \f
 
 }
 \f
 
@@ -3310,7 +4165,9 @@ lin_thread_get_thread_signals (sigset_t *set)
 {
   struct sigaction action;
   int restart, cancel;
 {
   struct sigaction action;
   int restart, cancel;
+  sigset_t blocked_mask;
 
 
+  sigemptyset (&blocked_mask);
   sigemptyset (set);
 
   restart = get_signo ("__pthread_sig_restart");
   sigemptyset (set);
 
   restart = get_signo ("__pthread_sig_restart");
This page took 0.053845 seconds and 4 git commands to generate.