* linux-nat.h (linux_proc_get_tgid): Declare.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 126f7dcb781222c90221d6f90a5d757290c0afe2..c3aa94fe3ad848cf7ac76b2f76041ee96cd2ae1a 100644 (file)
@@ -1,6 +1,6 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #include "inf-loop.h"
 #include "event-loop.h"
 #include "event-top.h"
+#include <pwd.h>
+#include <sys/types.h>
+#include "gdb_dirent.h"
+#include "xml-support.h"
 
 #ifdef HAVE_PERSONALITY
 # include <sys/personality.h>
@@ -85,48 +89,40 @@ notices it and returns.
 Waiting for events in async mode
 ================================
 
-In async mode, GDB should always be ready to handle both user input and target
-events, so neither blocking waitpid nor sigsuspend are viable
-options. Instead, we should notify the GDB main event loop whenever there's
-unprocessed event from the target.  The only way to notify this event loop is
-to make it wait on input from a pipe, and write something to the pipe whenever
-there's event. Obviously, if we fail to notify the event loop if there's
-target event, it's bad.  If we notify the event loop when there's no event
-from target, linux-nat.c will detect that there's no event, actually, and
-report event of type TARGET_WAITKIND_IGNORE, but it will waste time and
-better avoided.
-
-The main design point is that every time GDB is outside linux-nat.c, we have a
-SIGCHLD handler installed that is called when something happens to the target
-and notifies the GDB event loop. Also, the event is extracted from the target
-using waitpid and stored for future use.  Whenever GDB core decides to handle
-the event, and calls into linux-nat.c, we disable SIGCHLD and process things
-as in sync mode, except that before waitpid call we check if there are any
-previously read events.
-
-It could happen that during event processing, we'll try to get more events
-than there are events in the local queue, which will result to waitpid call.
-Those waitpid calls, while blocking, are guarantied to always have
-something for waitpid to return.  E.g., stopping a thread with SIGSTOP, and
-waiting for the lwp to stop.
-
-The event loop is notified about new events using a pipe. SIGCHLD handler does
-waitpid and writes the results in to a pipe. GDB event loop has the other end
-of the pipe among the sources. When event loop starts to process the event
-and calls a function in linux-nat.c, all events from the pipe are transferred
-into a local queue and SIGCHLD is blocked. Further processing goes as in sync
-mode. Before we return from linux_nat_wait, we transfer all unprocessed events
-from local queue back to the pipe, so that when we get back to event loop,
-event loop will notice there's something more to do.
-
-SIGCHLD is blocked when we're inside target_wait, so that should we actually
-want to wait for some more events, SIGCHLD handler does not steal them from
-us. Technically, it would be possible to add new events to the local queue but
-it's about the same amount of work as blocking SIGCHLD.
-
-This moving of events from pipe into local queue and back into pipe when we
-enter/leave linux-nat.c is somewhat ugly. Unfortunately, GDB event loop is
-home-grown and incapable to wait on any queue.
+In async mode, GDB should always be ready to handle both user input
+and target events, so neither blocking waitpid nor sigsuspend are
+viable options.  Instead, we should asynchronously notify the GDB main
+event loop whenever there's an unprocessed event from the target.  We
+detect asynchronous target events by handling SIGCHLD signals.  To
+notify the event loop about target events, the self-pipe trick is used
+--- a pipe is registered as waitable event source in the event loop,
+the event loop select/poll's on the read end of this pipe (as well on
+other event sources, e.g., stdin), and the SIGCHLD handler writes a
+byte to this pipe.  This is more portable than relying on
+pselect/ppoll, since on kernels that lack those syscalls, libc
+emulates them with select/poll+sigprocmask, and that is racy
+(a.k.a. plain broken).
+
+Obviously, if we fail to notify the event loop if there's a target
+event, it's bad.  OTOH, if we notify the event loop when there's no
+event from the target, linux_nat_wait will detect that there's no real
+event to report, and return event of type TARGET_WAITKIND_IGNORE.
+This is mostly harmless, but it will waste time and is better avoided.
+
+The main design point is that every time GDB is outside linux-nat.c,
+we have a SIGCHLD handler installed that is called when something
+happens to the target and notifies the GDB event loop.  Whenever GDB
+core decides to handle the event, and calls into linux-nat.c, we
+process things as in sync mode, except that the we never block in
+sigsuspend.
+
+While processing an event, we may end up momentarily blocked in
+waitpid calls.  Those waitpid calls, while blocking, are guarantied to
+return quickly.  E.g., in all-stop mode, before reporting to the core
+that an LWP hit a breakpoint, all LWPs are stopped by sending them
+SIGSTOP, and synchronously waiting for the SIGSTOP to be reported.
+Note that this is different from blocking indefinitely waiting for the
+next event --- here, we're already handling an event.
 
 Use of signals
 ==============
@@ -190,7 +186,8 @@ blocked.  */
 #endif
 
 #ifndef PTRACE_GETSIGINFO
-#define PTRACE_GETSIGINFO    0x4202
+# define PTRACE_GETSIGINFO    0x4202
+# define PTRACE_SETSIGINFO    0x4203
 #endif
 
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
@@ -201,6 +198,13 @@ 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 method to call, if any, when the siginfo object needs to be
+   converted between the layout returned by ptrace, and the layout in
+   the architecture of the inferior.  */
+static int (*linux_nat_siginfo_fixup) (struct siginfo *,
+                                      gdb_byte *,
+                                      int);
+
 /* 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 *, 
@@ -284,151 +288,55 @@ static int linux_nat_async_mask_value = 1;
    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;
-
-/* The possible SIGCHLD handling states.  */
-
-enum sigchld_state
-{
-  /* SIGCHLD disabled, with action set to sigchld_handler, for the
-     sigsuspend in linux_nat_wait.  */
-  sigchld_sync,
-  /* SIGCHLD enabled, with action set to async_sigchld_handler.  */
-  sigchld_async,
-  /* Set SIGCHLD to default action.  Used while creating an
-     inferior.  */
-  sigchld_default
-};
-
-/* The current SIGCHLD handling state.  */
-static enum sigchld_state linux_nat_async_events_state;
-
-static enum sigchld_state linux_nat_async_events (enum sigchld_state 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);
-static int kill_lwp (int lwpid, int signo);
-
-static int send_sigint_callback (struct lwp_info *lp, void *data);
-static int stop_callback (struct lwp_info *lp, void *data);
-
-/* 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;
+/* Flush the event pipe.  */
 
-static int
-queued_waitpid (int pid, int *status, int flags)
+static void
+async_file_flush (void)
 {
-  struct waitpid_result *msg = waitpid_queue, *prev = NULL;
-
-  if (debug_linux_nat_async)
-    fprintf_unfiltered (gdb_stdlog,
-                       "\
-QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n",
-                       linux_nat_async_events_state,
-                       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;
-    }
+  int ret;
+  char buf;
 
-  if (msg)
+  do
     {
-      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;
+      ret = read (linux_nat_event_pipe[0], &buf, 1);
     }
-
-  if (debug_linux_nat_async)
-    fprintf_unfiltered (gdb_stdlog, "QWPID: miss\n");
-
-  if (status)
-    *status = 0;
-  return -1;
+  while (ret >= 0 || (ret == -1 && errno == EINTR));
 }
 
+/* Put something (anything, doesn't matter what, or how much) in event
+   pipe, so that the select/poll in the event-loop realizes we have
+   something to process.  */
+
 static void
-push_waitpid (int pid, int status, int options)
+async_file_mark (void)
 {
-  struct waitpid_result *event, *new_event;
+  int ret;
 
-  new_event = xmalloc (sizeof (*new_event));
-  new_event->pid = pid;
-  new_event->status = status;
-  new_event->options = options;
-  new_event->next = NULL;
+  /* It doesn't really matter what the pipe contains, as long we end
+     up with something in it.  Might as well flush the previous
+     left-overs.  */
+  async_file_flush ();
 
-  if (waitpid_queue)
+  do
     {
-      for (event = waitpid_queue;
-          event && event->next;
-          event = event->next)
-       ;
-
-      event->next = new_event;
+      ret = write (linux_nat_event_pipe[1], "+", 1);
     }
-  else
-    waitpid_queue = new_event;
-}
+  while (ret == -1 && errno == EINTR);
 
-/* 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)
-    ;
+  /* Ignore EAGAIN.  If the pipe is full, the event loop will already
+     be awakened anyway.  */
 }
 
+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);
+static int kill_lwp (int lwpid, int signo);
+
+static int stop_callback (struct lwp_info *lp, void *data);
+
+static void block_child_signals (sigset_t *prev_mask);
+static void restore_child_signals_mask (sigset_t *prev_mask);
 \f
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
@@ -479,21 +387,13 @@ linux_tracefork_child (void)
   _exit (0);
 }
 
-/* Wrapper function for waitpid which handles EINTR, and checks for
-   locally queued events.  */
+/* Wrapper function for waitpid which handles EINTR.  */
 
 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_state == sigchld_sync);
-
-  ret = queued_waitpid (pid, status, flags);
-  if (ret != -1)
-    return ret;
-
   do
     {
       ret = waitpid (pid, status, flags);
@@ -521,16 +421,20 @@ linux_test_for_tracefork (int original_pid)
 {
   int child_pid, ret, status;
   long second_pid;
-  enum sigchld_state async_events_original_state;
+  sigset_t prev_mask;
 
-  async_events_original_state = linux_nat_async_events (sigchld_sync);
+  /* We don't want those ptrace calls to be interrupted.  */
+  block_child_signals (&prev_mask);
 
   linux_supports_tracefork_flag = 0;
   linux_supports_tracevforkdone_flag = 0;
 
   ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
   if (ret != 0)
-    return;
+    {
+      restore_child_signals_mask (&prev_mask);
+      return;
+    }
 
   child_pid = fork ();
   if (child_pid == -1)
@@ -554,7 +458,7 @@ linux_test_for_tracefork (int original_pid)
       if (ret != 0)
        {
          warning (_("linux_test_for_tracefork: failed to kill child"));
-         linux_nat_async_events (async_events_original_state);
+         restore_child_signals_mask (&prev_mask);
          return;
        }
 
@@ -565,7 +469,7 @@ linux_test_for_tracefork (int original_pid)
        warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
                 "killed child"), status);
 
-      linux_nat_async_events (async_events_original_state);
+      restore_child_signals_mask (&prev_mask);
       return;
     }
 
@@ -606,7 +510,7 @@ linux_test_for_tracefork (int original_pid)
     warning (_("linux_test_for_tracefork: failed to kill child"));
   my_waitpid (child_pid, &status, 0);
 
-  linux_nat_async_events (async_events_original_state);
+  restore_child_signals_mask (&prev_mask);
 }
 
 /* Return non-zero iff we have tracefork functionality available.
@@ -669,13 +573,13 @@ linux_child_post_startup_inferior (ptid_t ptid)
 static int
 linux_child_follow_fork (struct target_ops *ops, int follow_child)
 {
+  sigset_t prev_mask;
   ptid_t last_ptid;
   struct target_waitstatus last_status;
   int has_vforked;
   int parent_pid, child_pid;
 
-  if (target_can_async_p ())
-    target_async (NULL, 0);
+  block_child_signals (&prev_mask);
 
   get_last_target_status (&last_ptid, &last_status);
   has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
@@ -689,11 +593,15 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       /* We're already attached to the parent, by default. */
 
       /* Before detaching from the child, remove all breakpoints from
-         it.  (This won't actually modify the breakpoint list, but will
-         physically remove the breakpoints from the child.) */
-      /* If we vforked this will remove the breakpoints from the parent
-        also, but they'll be reinserted below.  */
-      detach_breakpoints (child_pid);
+         it.  If we forked, then this has already been taken care of
+         by infrun.c.  If we vforked however, any breakpoint inserted
+         in the parent is visible in the child, even those added while
+         stopped in a vfork catchpoint.  This won't actually modify
+         the breakpoint list, but will physically remove the
+         breakpoints from the child.  This will remove the breakpoints
+         from the parent also, but they'll be reinserted below.  */
+      if (has_vforked)
+       detach_breakpoints (child_pid);
 
       /* Detach new forked process?  */
       if (detach_fork)
@@ -711,6 +619,14 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       else
        {
          struct fork_info *fp;
+         struct inferior *parent_inf, *child_inf;
+
+         /* Add process to GDB's tables.  */
+         child_inf = add_inferior (child_pid);
+
+         parent_inf = find_inferior_pid (GET_PID (last_ptid));
+         child_inf->attach_flag = parent_inf->attach_flag;
+
          /* Retain child fork in ptrace (stopped) state.  */
          fp = find_fork_pid (child_pid);
          if (!fp)
@@ -774,11 +690,20 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
     }
   else
     {
+      struct thread_info *last_tp = find_thread_pid (last_ptid);
+      struct thread_info *tp;
       char child_pid_spelling[40];
+      struct inferior *parent_inf, *child_inf;
 
-      /* Needed to keep the breakpoint lists in sync.  */
-      if (! has_vforked)
-       detach_breakpoints (child_pid);
+      /* Copy user stepping state to the new inferior thread.  */
+      struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
+      CORE_ADDR step_range_start = last_tp->step_range_start;
+      CORE_ADDR step_range_end = last_tp->step_range_end;
+      struct frame_id step_frame_id = last_tp->step_frame_id;
+
+      /* Otherwise, deleting the parent would get rid of this
+        breakpoint.  */
+      last_tp->step_resume_breakpoint = NULL;
 
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
@@ -791,6 +716,14 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
                            child_pid);
        }
 
+      /* Add the new inferior first, so that the target_detach below
+        doesn't unpush the target.  */
+
+      child_inf = add_inferior (child_pid);
+
+      parent_inf = find_inferior_pid (GET_PID (last_ptid));
+      child_inf->attach_flag = parent_inf->attach_flag;
+
       /* If we're vforking, we may want to hold on to the parent until
         the child exits or execs.  At exec time we can remove the old
         breakpoints from the parent and detach it; at exit time we
@@ -810,7 +743,10 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
         safely resume it.  */
 
       if (has_vforked)
-       linux_parent_pid = parent_pid;
+       {
+         linux_parent_pid = parent_pid;
+         detach_inferior (parent_pid);
+       }
       else if (!detach_fork)
        {
          struct fork_info *fp;
@@ -819,26 +755,32 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          if (!fp)
            fp = add_fork (parent_pid);
          fork_save_infrun_state (fp, 0);
+
+         /* Also add an entry for the child fork.  */
+         fp = find_fork_pid (child_pid);
+         if (!fp)
+           fp = add_fork (child_pid);
+         fork_save_infrun_state (fp, 0);
        }
       else
        target_detach (NULL, 0);
 
       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);
       linux_nat_switch_fork (inferior_ptid);
       check_for_thread_db ();
 
+      tp = inferior_thread ();
+      tp->step_resume_breakpoint = step_resume_breakpoint;
+      tp->step_range_start = step_range_start;
+      tp->step_range_end = step_range_end;
+      tp->step_frame_id = step_frame_id;
+
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
     }
 
-  if (target_can_async_p ())
-    target_async (inferior_event_handler, 0);
-
+  restore_child_signals_mask (&prev_mask);
   return 0;
 }
 
@@ -899,9 +841,6 @@ linux_child_insert_exec_catchpoint (int pid)
 
 /* List of known LWPs.  */
 struct lwp_info *lwp_list;
-
-/* Number of LWPs in the list.  */
-static int num_lwps;
 \f
 
 /* Original signal mask.  */
@@ -911,19 +850,38 @@ static sigset_t normal_mask;
    _initialize_linux_nat.  */
 static sigset_t suspend_mask;
 
-/* SIGCHLD action for synchronous mode.  */
-struct sigaction sync_sigchld_action;
+/* Signals to block to make that sigsuspend work.  */
+static sigset_t blocked_mask;
+
+/* SIGCHLD action.  */
+struct sigaction sigchld_action;
+
+/* Block child signals (SIGCHLD and linux threads signals), and store
+   the previous mask in PREV_MASK.  */
+
+static void
+block_child_signals (sigset_t *prev_mask)
+{
+  /* Make sure SIGCHLD is blocked.  */
+  if (!sigismember (&blocked_mask, SIGCHLD))
+    sigaddset (&blocked_mask, SIGCHLD);
+
+  sigprocmask (SIG_BLOCK, &blocked_mask, prev_mask);
+}
 
-/* SIGCHLD action for asynchronous mode.  */
-static struct sigaction async_sigchld_action;
+/* Restore child signals mask, previously returned by
+   block_child_signals.  */
 
-/* SIGCHLD default action, to pass to new inferiors.  */
-static struct sigaction sigchld_default_action;
+static void
+restore_child_signals_mask (sigset_t *prev_mask)
+{
+  sigprocmask (SIG_SETMASK, prev_mask, NULL);
+}
 \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 int linux_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
 static int cancel_breakpoint (struct lwp_info *lp);
 
@@ -965,7 +923,48 @@ init_lwp_list (void)
     }
 
   lwp_list = NULL;
-  num_lwps = 0;
+}
+
+/* Remove all LWPs belong to PID from the lwp list.  */
+
+static void
+purge_lwp_list (int pid)
+{
+  struct lwp_info *lp, *lpprev, *lpnext;
+
+  lpprev = NULL;
+
+  for (lp = lwp_list; lp; lp = lpnext)
+    {
+      lpnext = lp->next;
+
+      if (ptid_get_pid (lp->ptid) == pid)
+       {
+         if (lp == lwp_list)
+           lwp_list = lp->next;
+         else
+           lpprev->next = lp->next;
+
+         xfree (lp);
+       }
+      else
+       lpprev = lp;
+    }
+}
+
+/* Return the number of known LWPs in the tgid given by PID.  */
+
+static int
+num_lwps (int pid)
+{
+  int count = 0;
+  struct lwp_info *lp;
+
+  for (lp = lwp_list; lp; lp = lp->next)
+    if (ptid_get_pid (lp->ptid) == pid)
+      count++;
+
+  return count;
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
@@ -989,9 +988,8 @@ add_lwp (ptid_t ptid)
 
   lp->next = lwp_list;
   lwp_list = lp;
-  ++num_lwps;
 
-  if (num_lwps > 1 && linux_nat_new_thread != NULL)
+  if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
     linux_nat_new_thread (ptid);
 
   return lp;
@@ -1013,8 +1011,6 @@ delete_lwp (ptid_t ptid)
   if (!lp)
     return;
 
-  num_lwps--;
-
   if (lpprev)
     lpprev->next = lp->next;
   else
@@ -1044,21 +1040,54 @@ find_lwp_pid (ptid_t ptid)
   return NULL;
 }
 
+/* Returns true if PTID matches filter FILTER.  FILTER can be the wild
+   card MINUS_ONE_PTID (all ptid match it); can be a ptid representing
+   a process (ptid_is_pid returns true), in which case, all lwps of
+   that give process match, lwps of other process do not; or, it can
+   represent a specific thread, in which case, only that thread will
+   match true.  PTID must represent an LWP, it can never be a wild
+   card.  */
+
+static int
+ptid_match (ptid_t ptid, ptid_t filter)
+{
+  /* Since both parameters have the same type, prevent easy mistakes
+     from happening.  */
+  gdb_assert (!ptid_equal (ptid, minus_one_ptid)
+             && !ptid_equal (ptid, null_ptid));
+
+  if (ptid_equal (filter, minus_one_ptid))
+    return 1;
+  if (ptid_is_pid (filter)
+      && ptid_get_pid (ptid) == ptid_get_pid (filter))
+    return 1;
+  else if (ptid_equal (ptid, filter))
+    return 1;
+
+  return 0;
+}
+
 /* Call CALLBACK with its second argument set to DATA for every LWP in
    the list.  If CALLBACK returns 1 for a particular LWP, return a
    pointer to the structure describing that LWP immediately.
    Otherwise return NULL.  */
 
 struct lwp_info *
-iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
+iterate_over_lwps (ptid_t filter,
+                  int (*callback) (struct lwp_info *, void *),
+                  void *data)
 {
   struct lwp_info *lp, *lpnext;
 
   for (lp = lwp_list; lp; lp = lpnext)
     {
       lpnext = lp->next;
-      if ((*callback) (lp, data))
-       return lp;
+
+      if (ptid_match (lp->ptid, filter))
+       {
+         if ((*callback) (lp, data))
+           return lp;
+       }
     }
 
   return NULL;
@@ -1100,6 +1129,34 @@ exit_lwp (struct lwp_info *lp)
   delete_lwp (lp->ptid);
 }
 
+/* Return an lwp's tgid, found in `/proc/PID/status'.  */
+
+int
+linux_proc_get_tgid (int lwpid)
+{
+  FILE *status_file;
+  char buf[100];
+  int tgid = -1;
+
+  snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
+  status_file = fopen (buf, "r");
+  if (status_file != NULL)
+    {
+      while (fgets (buf, sizeof (buf), status_file))
+       {
+         if (strncmp (buf, "Tgid:", 5) == 0)
+           {
+             tgid = strtoul (buf + strlen ("Tgid:"), NULL, 10);
+             break;
+           }
+       }
+
+      fclose (status_file);
+    }
+
+  return tgid;
+}
+
 /* Detect `T (stopped)' in `/proc/PID/status'.
    Other states including `T (tracing stop)' are reported as false.  */
 
@@ -1202,11 +1259,11 @@ int
 lin_lwp_attach_lwp (ptid_t ptid)
 {
   struct lwp_info *lp;
-  enum sigchld_state async_events_original_state;
+  sigset_t prev_mask;
 
   gdb_assert (is_lwp (ptid));
 
-  async_events_original_state = linux_nat_async_events (sigchld_sync);
+  block_child_signals (&prev_mask);
 
   lp = find_lwp_pid (ptid);
 
@@ -1229,6 +1286,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
             to create them.  */
          warning (_("Can't attach %s: %s"), target_pid_to_str (ptid),
                   safe_strerror (errno));
+         restore_child_signals_mask (&prev_mask);
          return -1;
        }
 
@@ -1271,12 +1329,13 @@ lin_lwp_attach_lwp (ptid_t ptid)
       lp->stopped = 1;
     }
 
-  linux_nat_async_events (async_events_original_state);
+  restore_child_signals_mask (&prev_mask);
   return 0;
 }
 
 static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
+linux_nat_create_inferior (struct target_ops *ops, 
+                          char *exec_file, char *allargs, char **env,
                           int from_tty)
 {
   int saved_async = 0;
@@ -1291,20 +1350,6 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
     /* Mask async mode.  Creating a child requires a loop calling
        wait_for_inferior currently.  */
     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);
-    }
-
-  /* Set SIGCHLD to the default action, until after execing the child,
-     since the inferior inherits the superior's signal mask.  It will
-     be blocked again in linux_nat_wait, which is only reached after
-     the inferior execing.  */
-  linux_nat_async_events (sigchld_default);
 
 #ifdef HAVE_PERSONALITY
   if (disable_randomization)
@@ -1323,7 +1368,7 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
     }
 #endif /* HAVE_PERSONALITY */
 
-  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+  linux_ops->to_create_inferior (ops, exec_file, allargs, env, from_tty);
 
 #ifdef HAVE_PERSONALITY
   if (personality_set)
@@ -1341,36 +1386,26 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
 }
 
 static void
-linux_nat_attach (char *args, int from_tty)
+linux_nat_attach (struct target_ops *ops, char *args, int from_tty)
 {
   struct lwp_info *lp;
   int status;
+  ptid_t ptid;
 
-  /* FIXME: We should probably accept a list of process id's, and
-     attach all of them.  */
-  linux_ops->to_attach (args, from_tty);
+  linux_ops->to_attach (ops, args, from_tty);
 
-  if (!target_can_async_p ())
-    {
-      /* Restore the original signal mask.  */
-      sigprocmask (SIG_SETMASK, &normal_mask, NULL);
-      /* Make sure we don't block SIGCHLD during a sigsuspend.  */
-      suspend_mask = normal_mask;
-      sigdelset (&suspend_mask, SIGCHLD);
-    }
+  /* The ptrace base target adds the main thread with (pid,0,0)
+     format.  Decorate it with lwp info.  */
+  ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  thread_change_ptid (inferior_ptid, ptid);
 
   /* 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 = add_lwp (ptid);
 
   status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned,
                                       &lp->signalled);
   lp->stopped = 1;
 
-  /* 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);
-
   /* Save the wait status to report later.  */
   lp->resumed = 1;
   if (debug_linux_nat)
@@ -1378,18 +1413,10 @@ linux_nat_attach (char *args, int from_tty)
                        "LNA: waitpid %ld, saving status %s\n",
                        (long) GET_PID (lp->ptid), status_to_str (status));
 
-  if (!target_can_async_p ())
-    lp->status = status;
-  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 (GET_PID (lp->ptid), status,
-                                lp->cloned ? __WCLONE : 0);
-      /* Register in the event loop.  */
-      target_async (inferior_event_handler, 0);
-    }
+  lp->status = status;
+
+  if (target_can_async_p ())
+    target_async (inferior_event_handler, 0);
 }
 
 /* Get pending status of LP.  */
@@ -1402,10 +1429,9 @@ get_pending_status (struct lwp_info *lp, int *status)
   get_last_target_status (&last_ptid, &last);
 
   /* If this lwp is the ptid that GDB is processing an event from, the
-     signal will be in stop_signal.  Otherwise, in all-stop + sync
-     mode, we may cache pending events in lp->status while trying to
-     stop all threads (see stop_wait_callback).  In async mode, the
-     events are always cached in waitpid_queue.  */
+     signal will be in stop_signal.  Otherwise, we may cache pending
+     events in lp->status while trying to stop all threads (see
+     stop_wait_callback).  */
 
   *status = 0;
 
@@ -1421,31 +1447,16 @@ get_pending_status (struct lwp_info *lp, int *status)
             stop_wait_callback sequence (see linux_nat_detach for
             example) --- we can only have pending events in the local
             queue.  */
-         if (queued_waitpid (GET_LWP (lp->ptid), status, __WALL) != -1)
-           {
-             if (WIFSTOPPED (status))
-               signo = target_signal_from_host (WSTOPSIG (status));
-
-             /* If not stopped, then the lwp is gone, no use in
-                resending a signal.  */
-           }
+         signo = target_signal_from_host (WSTOPSIG (lp->status));
        }
       else
        {
          /* If the core knows the thread is not executing, then we
             have the last signal recorded in
-            thread_info->stop_signal, unless this is inferior_ptid,
-            in which case, it's in the global stop_signal, due to
-            context switching.  */
+            thread_info->stop_signal.  */
 
-         if (ptid_equal (lp->ptid, inferior_ptid))
-           signo = stop_signal;
-         else
-           {
-             struct thread_info *tp = find_thread_pid (lp->ptid);
-             gdb_assert (tp);
-             signo = tp->stop_signal;
-           }
+         struct thread_info *tp = find_thread_pid (lp->ptid);
+         signo = tp->stop_signal;
        }
 
       if (signo != TARGET_SIGNAL_0
@@ -1473,12 +1484,11 @@ GPT: lwp %s had signal %s, but it is in no pass state\n",
     {
       if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
        {
-         if (stop_signal != TARGET_SIGNAL_0
-             && signal_pass_state (stop_signal))
-           *status = W_STOPCODE (target_signal_to_host (stop_signal));
+         struct thread_info *tp = find_thread_pid (lp->ptid);
+         if (tp->stop_signal != TARGET_SIGNAL_0
+             && signal_pass_state (tp->stop_signal))
+           *status = W_STOPCODE (target_signal_to_host (tp->stop_signal));
        }
-      else if (target_can_async_p ())
-       queued_waitpid (GET_LWP (lp->ptid), status, __WALL);
       else
        *status = lp->status;
     }
@@ -1527,7 +1537,7 @@ detach_callback (struct lwp_info *lp, void *data)
        fprintf_unfiltered (gdb_stdlog,
                            "PTRACE_DETACH (%s, %s, 0) (OK)\n",
                            target_pid_to_str (lp->ptid),
-                           strsignal (WSTOPSIG (lp->status)));
+                           strsignal (WSTOPSIG (status)));
 
       delete_lwp (lp->ptid);
     }
@@ -1536,30 +1546,35 @@ detach_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_detach (char *args, int from_tty)
+linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
 {
   int pid;
   int status;
   enum target_signal sig;
+  struct lwp_info *main_lwp;
+
+  pid = GET_PID (inferior_ptid);
 
   if (target_can_async_p ())
     linux_nat_async (NULL, 0);
 
   /* Stop all threads before detaching.  ptrace requires that the
      thread is stopped to sucessfully detach.  */
-  iterate_over_lwps (stop_callback, NULL);
+  iterate_over_lwps (pid_to_ptid (pid), stop_callback, NULL);
   /* ... and wait until all of them have reported back that
      they're no longer running.  */
-  iterate_over_lwps (stop_wait_callback, NULL);
+  iterate_over_lwps (pid_to_ptid (pid), stop_wait_callback, NULL);
 
-  iterate_over_lwps (detach_callback, NULL);
+  iterate_over_lwps (pid_to_ptid (pid), detach_callback, NULL);
 
   /* Only the initial process should be left right now.  */
-  gdb_assert (num_lwps == 1);
+  gdb_assert (num_lwps (GET_PID (inferior_ptid)) == 1);
+
+  main_lwp = find_lwp_pid (pid_to_ptid (pid));
 
   /* Pass on any pending signal for the last LWP.  */
   if ((args == NULL || *args == '\0')
-      && get_pending_status (lwp_list, &status) != -1
+      && get_pending_status (main_lwp, &status) != -1
       && WIFSTOPPED (status))
     {
       /* Put the signal number in ARGS so that inf_ptrace_detach will
@@ -1569,18 +1584,24 @@ linux_nat_detach (char *args, int from_tty)
       fprintf_unfiltered (gdb_stdlog,
                          "LND: Sending signal %s to %s\n",
                          args,
-                         target_pid_to_str (lwp_list->ptid));
+                         target_pid_to_str (main_lwp->ptid));
     }
 
-  /* Destroy LWP info; it's no longer valid.  */
-  init_lwp_list ();
-
-  pid = GET_PID (inferior_ptid);
-  inferior_ptid = pid_to_ptid (pid);
-  linux_ops->to_detach (args, from_tty);
+  delete_lwp (main_lwp->ptid);
 
-  if (target_can_async_p ())
-    drain_queued_events (pid);
+  if (forks_exist_p ())
+    {
+      /* Multi-fork case.  The current inferior_ptid is being detached
+        from, but there are other viable forks to debug.  Detach from
+        the current fork, and context-switch to the first
+        available.  */
+      linux_fork_detach (args, from_tty);
+
+      if (non_stop && target_can_async_p ())
+       target_async (inferior_event_handler, 0);
+    }
+  else
+    linux_ops->to_detach (ops, args, from_tty);
 }
 
 /* Resume LP.  */
@@ -1590,7 +1611,13 @@ resume_callback (struct lwp_info *lp, void *data)
 {
   if (lp->stopped && lp->status == 0)
     {
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
+                           target_pid_to_str (lp->ptid));
+
+      linux_ops->to_resume (linux_ops,
+                           pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -1625,10 +1652,12 @@ resume_set_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
+linux_nat_resume (struct target_ops *ops,
+                 ptid_t ptid, int step, enum target_signal signo)
 {
+  sigset_t prev_mask;
   struct lwp_info *lp;
-  int resume_all;
+  int resume_many;
 
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
@@ -1638,42 +1667,32 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
                        signo ? strsignal (signo) : "0",
                        target_pid_to_str (inferior_ptid));
 
-  if (target_can_async_p ())
-    /* Block events while we're here.  */
-    linux_nat_async_events (sigchld_sync);
+  block_child_signals (&prev_mask);
 
   /* A specific PTID means `step only this process id'.  */
-  resume_all = (PIDGET (ptid) == -1);
-
-  if (non_stop && resume_all)
-    internal_error (__FILE__, __LINE__,
-                   "can't resume all in non-stop mode");
+  resume_many = (ptid_equal (minus_one_ptid, ptid)
+                || ptid_is_pid (ptid));
 
   if (!non_stop)
     {
-      if (resume_all)
-       iterate_over_lwps (resume_set_callback, NULL);
-      else
-       iterate_over_lwps (resume_clear_callback, NULL);
+      /* Mark the lwps we're resuming as resumed.  */
+      iterate_over_lwps (minus_one_ptid, resume_clear_callback, NULL);
+      iterate_over_lwps (ptid, resume_set_callback, NULL);
     }
+  else
+    iterate_over_lwps (minus_one_ptid, resume_set_callback, NULL);
 
-  /* If PID is -1, it's the current inferior that should be
-     handled specially.  */
-  if (PIDGET (ptid) == -1)
-    ptid = inferior_ptid;
-
-  lp = find_lwp_pid (ptid);
+  /* See if it's the current inferior that should be handled
+     specially.  */
+  if (resume_many)
+    lp = find_lwp_pid (inferior_ptid);
+  else
+    lp = find_lwp_pid (ptid);
   gdb_assert (lp != NULL);
 
-  /* Convert to something the lower layer understands.  */
-  ptid = pid_to_ptid (GET_LWP (lp->ptid));
-
   /* Remember if we're stepping.  */
   lp->step = step;
 
-  /* Mark this LWP as resumed.  */
-  lp->resumed = 1;
-
   /* 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
@@ -1682,15 +1701,19 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
      other threads.  This bit of code needs to be synchronized
      with linux_nat_wait.  */
 
-  /* 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));
+      int saved_signo;
+      struct inferior *inf;
 
-      if (signal_stop_state (saved_signo) == 0
+      inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+      gdb_assert (inf);
+      saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+
+      /* Defer to common code if we're gaining control of the
+        inferior.  */
+      if (inf->stop_soon == NO_STOP_QUIETLY
+         && signal_stop_state (saved_signo) == 0
          && signal_print_state (saved_signo) == 0
          && signal_pass_state (saved_signo) == 1)
        {
@@ -1718,6 +1741,13 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
                            "LLR: Short circuiting for status 0x%x\n",
                            lp->status);
 
+      restore_child_signals_mask (&prev_mask);
+      if (target_can_async_p ())
+       {
+         target_async (inferior_event_handler, 0);
+         /* Tell the event loop we have something to process.  */
+         async_file_mark ();
+       }
       return;
     }
 
@@ -1725,10 +1755,13 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
      resume_callback.  */
   lp->stopped = 0;
 
-  if (resume_all)
-    iterate_over_lwps (resume_callback, NULL);
+  if (resume_many)
+    iterate_over_lwps (ptid, resume_callback, NULL);
 
-  linux_ops->to_resume (ptid, step, signo);
+  /* Convert to something the lower layer understands.  */
+  ptid = pid_to_ptid (GET_LWP (lp->ptid));
+
+  linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
 
   if (debug_linux_nat)
@@ -1738,6 +1771,7 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
                        target_pid_to_str (ptid),
                        signo ? strsignal (signo) : "0");
 
+  restore_child_signals_mask (&prev_mask);
   if (target_can_async_p ())
     target_async (inferior_event_handler, 0);
 }
@@ -1819,7 +1853,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
          struct cleanup *old_chain;
 
          ourstatus->kind = TARGET_WAITKIND_IGNORE;
-         new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
+         new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (lp->ptid)));
          new_lp->cloned = 1;
          new_lp->stopped = 1;
 
@@ -2163,40 +2197,21 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                 there are any more (we still want to get that SIGSTOP). */
              stop_wait_callback (lp, NULL);
 
-             if (target_can_async_p ())
+             /* Hold the SIGTRAP for handling by linux_nat_wait.  If
+                there's another event, throw it back into the
+                queue. */
+             if (lp->status)
                {
-                 /* Don't leave a pending wait status in async mode.
-                    Retrigger the breakpoint.  */
-                 if (!cancel_breakpoint (lp))
-                   {
-                     /* 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));
-                   }
-                 /* Save the sigtrap event. */
-                 lp->status = 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));
                }
+
+             /* Save the sigtrap event. */
+             lp->status = status;
              return 0;
            }
          else
@@ -2227,7 +2242,7 @@ stop_wait_callback (struct lwp_info *lp, void *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 || target_can_async_p ())
+             if (lp->status)
                {
                  if (debug_linux_nat)
                    {
@@ -2262,7 +2277,12 @@ status_callback (struct lwp_info *lp, void *data)
 {
   /* Only report a pending wait status if we pretend that this has
      indeed been resumed.  */
-  return (lp->status != 0 && lp->resumed);
+  /* We check for lp->waitstatus in addition to lp->status, because we
+     can have pending process exits recorded in lp->waitstatus, and
+     W_EXITCODE(0,0) == 0.  */
+  return ((lp->status != 0
+          || lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
+         && lp->resumed);
 }
 
 /* Return non-zero if LP isn't stopped.  */
@@ -2384,7 +2404,7 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
 /* Select one LWP out of those that have events pending.  */
 
 static void
-select_event_lwp (struct lwp_info **orig_lp, int *status)
+select_event_lwp (ptid_t filter, struct lwp_info **orig_lp, int *status)
 {
   int num_events = 0;
   int random_selector;
@@ -2394,7 +2414,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
   (*orig_lp)->status = *status;
 
   /* Give preference to any LWP that is being single-stepped.  */
-  event_lp = iterate_over_lwps (select_singlestep_lwp_callback, NULL);
+  event_lp = iterate_over_lwps (filter,
+                               select_singlestep_lwp_callback, NULL);
   if (event_lp != NULL)
     {
       if (debug_linux_nat)
@@ -2408,7 +2429,7 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
          which have had SIGTRAP events.  */
 
       /* First see how many SIGTRAP events we have.  */
-      iterate_over_lwps (count_events_callback, &num_events);
+      iterate_over_lwps (filter, count_events_callback, &num_events);
 
       /* Now randomly pick a LWP out of those that have had a SIGTRAP.  */
       random_selector = (int)
@@ -2419,7 +2440,8 @@ select_event_lwp (struct lwp_info **orig_lp, int *status)
                            "SEL: Found %d SIGTRAP events, selecting #%d\n",
                            num_events, random_selector);
 
-      event_lp = iterate_over_lwps (select_event_lwp_callback,
+      event_lp = iterate_over_lwps (filter,
+                                   select_event_lwp_callback,
                                    &random_selector);
     }
 
@@ -2537,11 +2559,12 @@ linux_nat_filter_event (int lwpid, int status, int options)
     }
 
   /* Check if the thread has exited.  */
-  if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
+  if ((WIFEXITED (status) || WIFSIGNALED (status))
+      && num_lwps (GET_PID (lp->ptid)) > 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
+      /* 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
+        on Linux 2.4, 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
@@ -2552,7 +2575,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
       if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
        {
          lp->stopped = 1;
-         iterate_over_lwps (stop_and_resume_callback, NULL);
+         iterate_over_lwps (pid_to_ptid (GET_PID (lp->ptid)),
+                            stop_and_resume_callback, NULL);
        }
 
       if (debug_linux_nat)
@@ -2560,21 +2584,24 @@ linux_nat_filter_event (int lwpid, int status, int options)
                            "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)
-       return NULL;
+      if (num_lwps (GET_PID (lp->ptid)) > 1)
+       {
+        /* If there is at least one more LWP, then the exit signal
+           was not the end of the debugged application and should be
+           ignored.  */
+        exit_lwp (lp);
+        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 (num_lwps (GET_PID (lp->ptid)) > 1 && !linux_thread_alive (lp->ptid))
     {
+      ptid_t ptid = pid_to_ptid (GET_PID (lp->ptid));
+
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLW: %s exited.\n",
@@ -2583,7 +2610,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
       exit_lwp (lp);
 
       /* Make sure there is at least one thread running.  */
-      gdb_assert (iterate_over_lwps (running_callback, NULL));
+      gdb_assert (iterate_over_lwps (ptid, running_callback, NULL));
 
       /* Discard the event.  */
       return NULL;
@@ -2604,7 +2631,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
 
       registers_changed ();
 
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2634,7 +2661,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
       lp->ignore_sigint = 0;
 
       registers_changed ();
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2655,99 +2682,61 @@ linux_nat_filter_event (int lwpid, int status, int options)
   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)
+static ptid_t
+linux_nat_wait_1 (struct target_ops *ops,
+                 ptid_t ptid, struct target_waitstatus *ourstatus)
 {
+  static sigset_t prev_mask;
+  struct lwp_info *lp = NULL;
+  int options = 0;
+  int status = 0;
+  pid_t pid;
+
   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)
+    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 (ptid_is_pid (inferior_ptid))
     {
-      int lwpid, status, options;
-      lwpid = linux_nat_event_pipe_pop (&status, &options);
-      gdb_assert (lwpid > 0);
-      push_waitpid (lwpid, status, options);
+      /* Upgrade the main thread's ptid.  */
+      thread_change_ptid (inferior_ptid,
+                         BUILD_LWP (GET_PID (inferior_ptid),
+                                    GET_PID (inferior_ptid)));
+
+      lp = add_lwp (inferior_ptid);
+      lp->resumed = 1;
     }
-}
 
-/* 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);
-
-  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);
-      set_running (lp->ptid, 1);
-      set_executing (lp->ptid, 1);
-    }
-
-  /* Block events while we're here.  */
-  linux_nat_async_events (sigchld_sync);
+  /* Make sure SIGCHLD is blocked.  */
+  block_child_signals (&prev_mask);
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    pid = -1;
+  else if (ptid_is_pid (ptid))
+    /* A request to wait for a specific tgid.  This is not possible
+       with waitpid, so instead, we wait for any child, and leave
+       children we're not interested in right now with a pending
+       status to report later.  */
+    pid = -1;
+  else
+    pid = GET_LWP (ptid);
 
 retry:
+  lp = NULL;
+  status = 0;
 
   /* Make sure there is at least one LWP that has been resumed.  */
-  gdb_assert (iterate_over_lwps (resumed_callback, NULL));
+  gdb_assert (iterate_over_lwps (ptid, 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);
+      lp = iterate_over_lwps (ptid, 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;
 
@@ -2759,8 +2748,8 @@ retry:
        }
 
       /* 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.  */
+        cloned and uncloned processes.  We start with the cloned
+        processes.  */
       options = __WCLONE | WNOHANG;
     }
   else if (is_lwp (ptid))
@@ -2787,9 +2776,16 @@ retry:
          the layer beneath us can understand.  */
       options = lp->cloned ? __WCLONE : 0;
       pid = GET_LWP (ptid);
+
+      /* We check for lp->waitstatus in addition to lp->status,
+        because we can have pending process exits recorded in
+        lp->status and W_EXITCODE(0,0) == 0.  We should probably have
+        an additional lp->status_p flag.  */
+      if (status == 0 && lp->waitstatus.kind == TARGET_WAITKIND_IGNORE)
+       lp = NULL;
     }
 
-  if (status && lp->signalled)
+  if (lp && lp->signalled)
     {
       /* A pending SIGSTOP may interfere with the normal stream of
          events.  In a typical case where interference is a problem,
@@ -2803,7 +2799,7 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
-      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+      linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -2821,19 +2817,16 @@ retry:
     {
       /* Causes SIGINT to be passed on to the attached process.  */
       set_sigint_trap ();
-      set_sigio_trap ();
     }
 
-  while (status == 0)
+  if (target_can_async_p ())
+    options |= WNOHANG; /* In async mode, don't block.  */
+
+  while (lp == NULL)
     {
       pid_t lwpid;
 
-      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);
+      lwpid = my_waitpid (pid, &status, options);
 
       if (lwpid > 0)
        {
@@ -2847,14 +2840,79 @@ retry:
            }
 
          lp = linux_nat_filter_event (lwpid, status, options);
-         if (!lp)
+
+         if (lp
+             && ptid_is_pid (ptid)
+             && ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
            {
-             /* A discarded event.  */
-             status = 0;
+             if (debug_linux_nat)
+               fprintf (stderr, "LWP %ld got an event %06x, leaving pending.\n",
+                        ptid_get_lwp (lp->ptid), status);
+
+             if (WIFSTOPPED (status))
+               {
+                 if (WSTOPSIG (status) != SIGSTOP)
+                   {
+                     lp->status = status;
+
+                     stop_callback (lp, NULL);
+
+                     /* Resume in order to collect the sigstop.  */
+                     ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+
+                     stop_wait_callback (lp, NULL);
+                   }
+                 else
+                   {
+                     lp->stopped = 1;
+                     lp->signalled = 0;
+                   }
+               }
+             else if (WIFEXITED (status) || WIFSIGNALED (status))
+               {
+                 if (debug_linux_nat)
+                   fprintf (stderr, "Process %ld exited while stopping LWPs\n",
+                            ptid_get_lwp (lp->ptid));
+
+                 /* This was the last lwp in the process.  Since
+                    events are serialized to GDB core, and we can't
+                    report this one right now, but GDB core and the
+                    other target layers will want to be notified
+                    about the exit code/signal, leave the status
+                    pending for the next time we're able to report
+                    it.  */
+                 lp->status = status;
+
+                 /* Prevent trying to stop this thread again.  We'll
+                    never try to resume it because it has a pending
+                    status.  */
+                 lp->stopped = 1;
+
+                 /* Dead LWP's aren't expected to reported a pending
+                    sigstop.  */
+                 lp->signalled = 0;
+
+                 /* Store the pending event in the waitstatus as
+                    well, because W_EXITCODE(0,0) == 0.  */
+                 store_waitstatus (&lp->waitstatus, status);
+               }
+
+             /* Keep looking.  */
+             lp = NULL;
              continue;
            }
 
-         break;
+         if (lp)
+           break;
+         else
+           {
+             if (pid == -1)
+               {
+                 /* waitpid did return something.  Restart over.  */
+                 options |= __WCLONE;
+               }
+             continue;
+           }
        }
 
       if (pid == -1)
@@ -2872,12 +2930,10 @@ retry:
                  /* 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");
 
+                 restore_child_signals_mask (&prev_mask);
                  return minus_one_ptid;
                }
 
@@ -2886,14 +2942,11 @@ retry:
        }
 
       /* We shouldn't end up here unless we want to try again.  */
-      gdb_assert (status == 0);
+      gdb_assert (lp == NULL);
     }
 
   if (!target_can_async_p ())
-    {
-      clear_sigio_trap ();
-      clear_sigint_trap ();
-    }
+    clear_sigint_trap ();
 
   gdb_assert (lp);
 
@@ -2907,10 +2960,17 @@ retry:
   if (WIFSTOPPED (status))
     {
       int signo = target_signal_from_host (WSTOPSIG (status));
+      struct inferior *inf;
+
+      inf = find_inferior_pid (ptid_get_pid (lp->ptid));
+      gdb_assert (inf);
 
-      /* If we get a signal while single-stepping, we may need special
-        care, e.g. to skip the signal handler.  Defer to common code.  */
+      /* Defer to common code if we get a signal while
+        single-stepping, since that may need special care, e.g. to
+        skip the signal handler, or, if we're gaining control of the
+        inferior.  */
       if (!lp->step
+         && inf->stop_soon == NO_STOP_QUIETLY
          && signal_stop_state (signo) == 0
          && signal_print_state (signo) == 0
          && signal_pass_state (signo) == 1)
@@ -2921,7 +2981,7 @@ retry:
             newly attached threads may cause an unwanted delay in
             getting them running.  */
          registers_changed ();
-         linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+         linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                                lp->step, signo);
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
@@ -2931,22 +2991,28 @@ retry:
                                target_pid_to_str (lp->ptid),
                                signo ? strsignal (signo) : "0");
          lp->stopped = 0;
-         status = 0;
          goto retry;
        }
 
-      if (signo == TARGET_SIGNAL_INT && signal_pass_state (signo) == 0)
+      if (!non_stop)
        {
-         /* If ^C/BREAK is typed at the tty/console, SIGINT gets
-            forwarded to the entire process group, that is, all LWPs
-            will receive it - unless they're using CLONE_THREAD to
-            share signals.  Since we only want to report it once, we
-            mark it as ignored for all LWPs except this one.  */
-         iterate_over_lwps (set_ignore_sigint, NULL);
-         lp->ignore_sigint = 0;
+         /* Only do the below in all-stop, as we currently use SIGINT
+            to implement target_stop (see linux_nat_stop) in
+            non-stop.  */
+         if (signo == TARGET_SIGNAL_INT && signal_pass_state (signo) == 0)
+           {
+             /* If ^C/BREAK is typed at the tty/console, SIGINT gets
+                forwarded to the entire process group, that is, all LWPs
+                will receive it - unless they're using CLONE_THREAD to
+                share signals.  Since we only want to report it once, we
+                mark it as ignored for all LWPs except this one.  */
+             iterate_over_lwps (pid_to_ptid (ptid_get_pid (ptid)),
+                                             set_ignore_sigint, NULL);
+             lp->ignore_sigint = 0;
+           }
+         else
+           maybe_clear_ignore_sigint (lp);
        }
-      else
-       maybe_clear_ignore_sigint (lp);
     }
 
   /* This LWP is stopped now.  */
@@ -2959,24 +3025,24 @@ retry:
   if (!non_stop)
     {
       /* Now stop all other LWP's ...  */
-      iterate_over_lwps (stop_callback, NULL);
+      iterate_over_lwps (minus_one_ptid, stop_callback, NULL);
 
       /* ... and wait until all of them have reported back that
         they're no longer running.  */
-      iterate_over_lwps (stop_wait_callback, NULL);
+      iterate_over_lwps (minus_one_ptid, stop_wait_callback, NULL);
 
       /* If we're not waiting for a specific LWP, choose an event LWP
         from among those that have had events.  Giving equal priority
         to all LWPs that have had events helps prevent
         starvation.  */
       if (pid == -1)
-       select_event_lwp (&lp, &status);
+       select_event_lwp (ptid, &lp, &status);
     }
 
   /* Now that we've selected our final event LWP, cancel any
      breakpoints in other LWPs that have hit a GDB breakpoint.  See
      the comment in cancel_breakpoints_callback to find out why.  */
-  iterate_over_lwps (cancel_breakpoints_callback, lp);
+  iterate_over_lwps (minus_one_ptid, cancel_breakpoints_callback, lp);
 
   if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
     {
@@ -2994,16 +3060,43 @@ retry:
   else
     store_waitstatus (ourstatus, status);
 
-  /* Get ready for the next event.  */
-  if (target_can_async_p ())
-    target_async (inferior_event_handler, 0);
-
   if (debug_linux_nat_async)
     fprintf_unfiltered (gdb_stdlog, "LLW: exit\n");
 
+  restore_child_signals_mask (&prev_mask);
   return lp->ptid;
 }
 
+static ptid_t
+linux_nat_wait (struct target_ops *ops,
+               ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  ptid_t event_ptid;
+
+  if (debug_linux_nat)
+    fprintf_unfiltered (gdb_stdlog, "linux_nat_wait: [%s]\n", target_pid_to_str (ptid));
+
+  /* Flush the async file first.  */
+  if (target_can_async_p ())
+    async_file_flush ();
+
+  event_ptid = linux_nat_wait_1 (ops, ptid, ourstatus);
+
+  /* If we requested any event, and something came out, assume there
+     may be more.  If we requested a specific lwp or process, also
+     assume there may be more.  */
+  if (target_can_async_p ()
+      && (ourstatus->kind != TARGET_WAITKIND_IGNORE
+         || !ptid_equal (ptid, minus_one_ptid)))
+    async_file_mark ();
+
+  /* Get ready for the next event.  */
+  if (target_can_async_p ())
+    target_async (inferior_event_handler, 0);
+
+  return event_ptid;
+}
+
 static int
 kill_callback (struct lwp_info *lp, void *data)
 {
@@ -3074,15 +3167,12 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 }
 
 static void
-linux_nat_kill (void)
+linux_nat_kill (struct target_ops *ops)
 {
   struct target_waitstatus last;
   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.  */
@@ -3097,42 +3187,35 @@ linux_nat_kill (void)
     }
 
   if (forks_exist_p ())
-    {
-      linux_fork_killall ();
-      drain_queued_events (-1);
-    }
+    linux_fork_killall ();
   else
     {
+      ptid_t ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
       /* Stop all threads before killing them, since ptrace requires
         that the thread is stopped to sucessfully PTRACE_KILL.  */
-      iterate_over_lwps (stop_callback, NULL);
+      iterate_over_lwps (ptid, stop_callback, NULL);
       /* ... and wait until all of them have reported back that
         they're no longer running.  */
-      iterate_over_lwps (stop_wait_callback, NULL);
+      iterate_over_lwps (ptid, stop_wait_callback, NULL);
 
       /* Kill all LWP's ...  */
-      iterate_over_lwps (kill_callback, NULL);
+      iterate_over_lwps (ptid, kill_callback, NULL);
 
       /* ... and wait until we've flushed all events.  */
-      iterate_over_lwps (kill_wait_callback, NULL);
+      iterate_over_lwps (ptid, kill_wait_callback, NULL);
     }
 
   target_mourn_inferior ();
 }
 
 static void
-linux_nat_mourn_inferior (void)
+linux_nat_mourn_inferior (struct target_ops *ops)
 {
-  /* Destroy LWP info; it's no longer valid.  */
-  init_lwp_list ();
+  purge_lwp_list (ptid_get_pid (inferior_ptid));
 
   if (! forks_exist_p ())
-    {
-      /* Normal case, no other forks available.  */
-      if (target_can_async_p ())
-       linux_nat_async (NULL, 0);
-      linux_ops->to_mourn_inferior ();
-    }
+    /* Normal case, no other forks available.  */
+    linux_ops->to_mourn_inferior (ops);
   else
     /* Multi-fork case.  The current inferior_ptid has exited, but
        there are other viable forks to debug.  Delete the exiting
@@ -3140,15 +3223,96 @@ linux_nat_mourn_inferior (void)
     linux_fork_mourn_inferior ();
 }
 
+/* Convert a native/host siginfo object, into/from the siginfo in the
+   layout of the inferiors' architecture.  */
+
+static void
+siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+{
+  int done = 0;
+
+  if (linux_nat_siginfo_fixup != NULL)
+    done = linux_nat_siginfo_fixup (siginfo, inf_siginfo, direction);
+
+  /* If there was no callback, or the callback didn't do anything,
+     then just do a straight memcpy.  */
+  if (!done)
+    {
+      if (direction == 1)
+       memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+      else
+       memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+    }
+}
+
+static LONGEST
+linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte *readbuf,
+                   const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  int pid;
+  struct siginfo siginfo;
+  gdb_byte inf_siginfo[sizeof (struct siginfo)];
+
+  gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
+  gdb_assert (readbuf || writebuf);
+
+  pid = GET_LWP (inferior_ptid);
+  if (pid == 0)
+    pid = GET_PID (inferior_ptid);
+
+  if (offset > sizeof (siginfo))
+    return -1;
+
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+  if (errno != 0)
+    return -1;
+
+  /* When GDB is built as a 64-bit application, ptrace writes into
+     SIGINFO an object with 64-bit layout.  Since debugging a 32-bit
+     inferior with a 64-bit GDB should look the same as debugging it
+     with a 32-bit GDB, we need to convert it.  GDB core always sees
+     the converted layout, so any read/write will have to be done
+     post-conversion.  */
+  siginfo_fixup (&siginfo, inf_siginfo, 0);
+
+  if (offset + len > sizeof (siginfo))
+    len = sizeof (siginfo) - offset;
+
+  if (readbuf != NULL)
+    memcpy (readbuf, inf_siginfo + offset, len);
+  else
+    {
+      memcpy (inf_siginfo + offset, writebuf, len);
+
+      /* Convert back to ptrace layout before flushing it out.  */
+      siginfo_fixup (&siginfo, inf_siginfo, 1);
+
+      errno = 0;
+      ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+      if (errno != 0)
+       return -1;
+    }
+
+  return len;
+}
+
 static LONGEST
 linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
                        const char *annex, gdb_byte *readbuf,
                        const gdb_byte *writebuf,
                        ULONGEST offset, LONGEST len)
 {
-  struct cleanup *old_chain = save_inferior_ptid ();
+  struct cleanup *old_chain;
   LONGEST xfer;
 
+  if (object == TARGET_OBJECT_SIGNAL_INFO)
+    return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf,
+                              offset, len);
+
+  old_chain = save_inferior_ptid ();
+
   if (is_lwp (inferior_ptid))
     inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
 
@@ -3160,7 +3324,7 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
 }
 
 static int
-linux_nat_thread_alive (ptid_t ptid)
+linux_thread_alive (ptid_t ptid)
 {
   int err;
 
@@ -3183,14 +3347,20 @@ linux_nat_thread_alive (ptid_t ptid)
   return 1;
 }
 
+static int
+linux_nat_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+  return linux_thread_alive (ptid);
+}
+
 static char *
-linux_nat_pid_to_str (ptid_t ptid)
+linux_nat_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
   static char buf[64];
 
   if (is_lwp (ptid)
-      && ((lwp_list && lwp_list->next)
-         || GET_PID (ptid) != GET_LWP (ptid)))
+      && (GET_PID (ptid) != GET_LWP (ptid)
+         || num_lwps (GET_PID (ptid)) > 1))
     {
       snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
       return buf;
@@ -3199,21 +3369,6 @@ linux_nat_pid_to_str (ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
-static void
-sigchld_handler (int signo)
-{
-  if (target_async_permitted
-      && linux_nat_async_events_state != sigchld_sync
-      && 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.  */
-}
-
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
@@ -3272,18 +3427,20 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
                                            unsigned long,
                                            int, int, int, void *), void *obfd)
 {
-  long long pid = PIDGET (inferior_ptid);
+  int pid = PIDGET (inferior_ptid);
   char mapsfilename[MAXPATHLEN];
   FILE *mapsfile;
   long long addr, endaddr, size, offset, inode;
   char permissions[8], device[8], filename[MAXPATHLEN];
   int read, write, exec;
   int ret;
+  struct cleanup *cleanup;
 
   /* Compose the filename for the /proc memory map, and open it.  */
-  sprintf (mapsfilename, "/proc/%lld/maps", pid);
+  sprintf (mapsfilename, "/proc/%d/maps", pid);
   if ((mapsfile = fopen (mapsfilename, "r")) == NULL)
     error (_("Could not open %s."), mapsfilename);
+  cleanup = make_cleanup_fclose (mapsfile);
 
   if (info_verbose)
     fprintf_filtered (gdb_stdout,
@@ -3316,16 +3473,39 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
         segment.  */
       func (addr, size, read, write, exec, obfd);
     }
-  fclose (mapsfile);
+  do_cleanups (cleanup);
   return 0;
 }
 
+static int
+find_signalled_thread (struct thread_info *info, void *data)
+{
+  if (info->stop_signal != TARGET_SIGNAL_0
+      && ptid_get_pid (info->ptid) == ptid_get_pid (inferior_ptid))
+    return 1;
+
+  return 0;
+}
+
+static enum target_signal
+find_stop_signal (void)
+{
+  struct thread_info *info =
+    iterate_over_threads (find_signalled_thread, NULL);
+
+  if (info)
+    return info->stop_signal;
+  else
+    return TARGET_SIGNAL_0;
+}
+
 /* Records the thread's register state for the corefile note
    section.  */
 
 static char *
 linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
-                              char *note_data, int *note_size)
+                              char *note_data, int *note_size,
+                              enum target_signal stop_signal)
 {
   gdb_gregset_t gregs;
   gdb_fpregset_t fpregs;
@@ -3420,6 +3600,7 @@ struct linux_nat_corefile_thread_data
   char *note_data;
   int *note_size;
   int num_notes;
+  enum target_signal stop_signal;
 };
 
 /* Called by gdbthread.c once per thread.  Records the thread's
@@ -3433,25 +3614,13 @@ linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
   args->note_data = linux_nat_do_thread_registers (args->obfd,
                                                   ti->ptid,
                                                   args->note_data,
-                                                  args->note_size);
+                                                  args->note_size,
+                                                  args->stop_signal);
   args->num_notes++;
 
   return 0;
 }
 
-/* Records the register state for the corefile note section.  */
-
-static char *
-linux_nat_do_registers (bfd *obfd, ptid_t ptid,
-                       char *note_data, int *note_size)
-{
-  return linux_nat_do_thread_registers (obfd,
-                                       ptid_build (ptid_get_pid (inferior_ptid),
-                                                   ptid_get_pid (inferior_ptid),
-                                                   0),
-                                       note_data, note_size);
-}
-
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
    section for a corefile, and returns it in a malloc buffer.  */
 
@@ -3466,6 +3635,7 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
+  ptid_t filter = pid_to_ptid (ptid_get_pid (inferior_ptid));
   gdb_byte *auxv;
   int auxv_len;
 
@@ -3498,18 +3668,10 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
   thread_args.note_data = note_data;
   thread_args.note_size = note_size;
   thread_args.num_notes = 0;
-  iterate_over_lwps (linux_nat_corefile_thread_callback, &thread_args);
-  if (thread_args.num_notes == 0)
-    {
-      /* iterate_over_threads didn't come up with any threads; just
-         use inferior_ptid.  */
-      note_data = linux_nat_do_registers (obfd, inferior_ptid,
-                                         note_data, note_size);
-    }
-  else
-    {
-      note_data = thread_args.note_data;
-    }
+  thread_args.stop_signal = find_stop_signal ();
+  iterate_over_lwps (filter, linux_nat_corefile_thread_callback, &thread_args);
+  gdb_assert (thread_args.num_notes != 0);
+  note_data = thread_args.note_data;
 
   auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
                                NULL, &auxv);
@@ -3529,7 +3691,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 static void
 linux_nat_info_proc_cmd (char *args, int from_tty)
 {
-  long long pid = PIDGET (inferior_ptid);
+  /* A long is used for pid instead of an int to avoid a loss of precision
+     compiler warning from the output of strtoul.  */
+  long pid = PIDGET (inferior_ptid);
   FILE *procfile;
   char **argv = NULL;
   char buffer[MAXPATHLEN];
@@ -3547,10 +3711,8 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (args)
     {
       /* Break up 'args' into an argv array.  */
-      if ((argv = buildargv (args)) == NULL)
-       nomem (0);
-      else
-       make_cleanup_freeargv (argv);
+      argv = gdb_buildargv (args);
+      make_cleanup_freeargv (argv);
     }
   while (argv != NULL && *argv != NULL)
     {
@@ -3595,26 +3757,29 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (pid == 0)
     error (_("No current process: you must name one."));
 
-  sprintf (fname1, "/proc/%lld", pid);
+  sprintf (fname1, "/proc/%ld", pid);
   if (stat (fname1, &dummy) != 0)
     error (_("No /proc directory: '%s'"), fname1);
 
-  printf_filtered (_("process %lld\n"), pid);
+  printf_filtered (_("process %ld\n"), pid);
   if (cmdline_f || all)
     {
-      sprintf (fname1, "/proc/%lld/cmdline", pid);
+      sprintf (fname1, "/proc/%ld/cmdline", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
-         fgets (buffer, sizeof (buffer), procfile);
-         printf_filtered ("cmdline = '%s'\n", buffer);
-         fclose (procfile);
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
+          if (fgets (buffer, sizeof (buffer), procfile))
+            printf_filtered ("cmdline = '%s'\n", buffer);
+          else
+            warning (_("unable to read '%s'"), fname1);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (cwd_f || all)
     {
-      sprintf (fname1, "/proc/%lld/cwd", pid);
+      sprintf (fname1, "/proc/%ld/cwd", pid);
       memset (fname2, 0, sizeof (fname2));
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("cwd = '%s'\n", fname2);
@@ -3623,7 +3788,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
   if (exe_f || all)
     {
-      sprintf (fname1, "/proc/%lld/exe", pid);
+      sprintf (fname1, "/proc/%ld/exe", pid);
       memset (fname2, 0, sizeof (fname2));
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("exe = '%s'\n", fname2);
@@ -3632,12 +3797,14 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
   if (mappings_f || all)
     {
-      sprintf (fname1, "/proc/%lld/maps", pid);
+      sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
          long long addr, endaddr, size, offset, inode;
          char permissions[8], device[8], filename[MAXPATHLEN];
+         struct cleanup *cleanup;
 
+         cleanup = make_cleanup_fclose (procfile);
          printf_filtered (_("Mapped address spaces:\n\n"));
          if (gdbarch_addr_bit (current_gdbarch) == 32)
            {
@@ -3685,31 +3852,33 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
                }
            }
 
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (status_f || all)
     {
-      sprintf (fname1, "/proc/%lld/status", pid);
+      sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
          while (fgets (buffer, sizeof (buffer), procfile) != NULL)
            puts_filtered (buffer);
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (stat_f || all)
     {
-      sprintf (fname1, "/proc/%lld/stat", pid);
+      sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
        {
          int itmp;
          char ctmp;
          long ltmp;
+         struct cleanup *cleanup = make_cleanup_fclose (procfile);
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
@@ -3793,7 +3962,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
            printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
-         fclose (procfile);
+         do_cleanups (cleanup);
        }
       else
        warning (_("unable to open /proc file '%s'"), fname1);
@@ -3895,6 +4064,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   FILE *procfile;
   char buffer[MAXPATHLEN], fname[MAXPATHLEN];
   int signum;
+  struct cleanup *cleanup;
 
   sigemptyset (pending);
   sigemptyset (blocked);
@@ -3903,6 +4073,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   procfile = fopen (fname, "r");
   if (procfile == NULL)
     error (_("Could not open %s"), fname);
+  cleanup = make_cleanup_fclose (procfile);
 
   while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
     {
@@ -3924,7 +4095,114 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
        add_line_to_sigset (buffer + 8, ignored);
     }
 
-  fclose (procfile);
+  do_cleanups (cleanup);
+}
+
+static LONGEST
+linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte *readbuf,
+                    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  /* We make the process list snapshot when the object starts to be
+     read.  */
+  static const char *buf;
+  static LONGEST len_avail = -1;
+  static struct obstack obstack;
+
+  DIR *dirp;
+
+  gdb_assert (object == TARGET_OBJECT_OSDATA);
+
+  if (strcmp (annex, "processes") != 0)
+    return 0;
+
+  gdb_assert (readbuf && !writebuf);
+
+  if (offset == 0)
+    {
+      if (len_avail != -1 && len_avail != 0)
+       obstack_free (&obstack, NULL);
+      len_avail = 0;
+      buf = NULL;
+      obstack_init (&obstack);
+      obstack_grow_str (&obstack, "<osdata type=\"processes\">\n");
+
+      dirp = opendir ("/proc");
+      if (dirp)
+       {
+         struct dirent *dp;
+         while ((dp = readdir (dirp)) != NULL)
+           {
+             struct stat statbuf;
+             char procentry[sizeof ("/proc/4294967295")];
+
+             if (!isdigit (dp->d_name[0])
+                 || NAMELEN (dp) > sizeof ("4294967295") - 1)
+               continue;
+
+             sprintf (procentry, "/proc/%s", dp->d_name);
+             if (stat (procentry, &statbuf) == 0
+                 && S_ISDIR (statbuf.st_mode))
+               {
+                 char *pathname;
+                 FILE *f;
+                 char cmd[MAXPATHLEN + 1];
+                 struct passwd *entry;
+
+                 pathname = xstrprintf ("/proc/%s/cmdline", dp->d_name);
+                 entry = getpwuid (statbuf.st_uid);
+
+                 if ((f = fopen (pathname, "r")) != NULL)
+                   {
+                     size_t len = fread (cmd, 1, sizeof (cmd) - 1, f);
+                     if (len > 0)
+                       {
+                         int i;
+                         for (i = 0; i < len; i++)
+                           if (cmd[i] == '\0')
+                             cmd[i] = ' ';
+                         cmd[len] = '\0';
+
+                         obstack_xml_printf (
+                          &obstack,
+                          "<item>"
+                          "<column name=\"pid\">%s</column>"
+                          "<column name=\"user\">%s</column>"
+                          "<column name=\"command\">%s</column>"
+                          "</item>",
+                          dp->d_name,
+                          entry ? entry->pw_name : "?",
+                          cmd);
+                       }
+                     fclose (f);
+                   }
+
+                 xfree (pathname);
+               }
+           }
+
+         closedir (dirp);
+       }
+
+      obstack_grow_str0 (&obstack, "</osdata>\n");
+      buf = obstack_finish (&obstack);
+      len_avail = strlen (buf);
+    }
+
+  if (offset >= len_avail)
+    {
+      /* Done.  Get rid of the obstack.  */
+      obstack_free (&obstack, NULL);
+      buf = NULL;
+      len_avail = 0;
+      return 0;
+    }
+
+  if (len > len_avail - offset)
+    len = len_avail - offset;
+  memcpy (readbuf, buf + offset, len);
+
+  return len;
 }
 
 static LONGEST
@@ -3938,6 +4216,10 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
     return procfs_xfer_auxv (ops, object, annex, readbuf, writebuf,
                             offset, len);
 
+  if (object == TARGET_OBJECT_OSDATA)
+    return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf,
+                               offset, len);
+
   xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf,
                                  offset, len);
   if (xfer != 0)
@@ -3995,12 +4277,13 @@ 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 target-async" command.
+     it explicitly with the "set target-async" command.
      Someday, linux will always be async.  */
   if (!target_async_permitted)
     return 0;
 
-  return 1;
+  /* See target.h/target_async_mask.  */
+  return linux_nat_async_mask_value;
 }
 
 /* target_can_async_p implementation.  */
@@ -4009,7 +4292,7 @@ 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 target-async" command.
+     it explicitly with the "set target-async" command.
      Someday, linux will always be async.  */
   if (!target_async_permitted)
     return 0;
@@ -4024,208 +4307,46 @@ linux_nat_supports_non_stop (void)
   return 1;
 }
 
-/* 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;
-       }
-      else
-       {
-         linux_nat_async_mask_value = mask;
-         linux_nat_async (inferior_event_handler, 0);
-       }
-    }
-
-  return current_state;
-}
+/* True if we want to support multi-process.  To be removed when GDB
+   supports multi-exec.  */
 
-/* Pop an event from the event pipe.  */
+int linux_multi_process = 0;
 
 static int
-linux_nat_event_pipe_pop (int* ptr_status, int* ptr_options)
+linux_nat_supports_multi_process (void)
 {
-  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;
+  return linux_multi_process;
 }
 
-/* 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++;
-}
+/* target_async_mask implementation.  */
 
-static void
-get_pending_events (void)
+static int
+linux_nat_async_mask (int new_mask)
 {
-  int status, options, pid;
-
-  if (!target_async_permitted
-      || linux_nat_async_events_state != sigchld_async)
-    internal_error (__FILE__, __LINE__,
-                   "get_pending_events called with async masked");
+  int curr_mask = linux_nat_async_mask_value;
 
-  while (1)
+  if (curr_mask != new_mask)
     {
-      status = 0;
-      options = __WCLONE | WNOHANG;
-
-      do
-       {
-         pid = waitpid (-1, &status, options);
-       }
-      while (pid == -1 && errno == EINTR);
-
-      if (pid <= 0)
+      if (new_mask == 0)
        {
-         options = WNOHANG;
-         do
-           {
-             pid = waitpid (-1, &status, options);
-           }
-         while (pid == -1 && errno == EINTR);
+         linux_nat_async (NULL, 0);
+         linux_nat_async_mask_value = new_mask;
        }
-
-      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 ();
-}
-
-/* Set SIGCHLD handling state to STATE.  Returns previous state.  */
-
-static enum sigchld_state
-linux_nat_async_events (enum sigchld_state state)
-{
-  enum sigchld_state current_state = linux_nat_async_events_state;
-
-  if (debug_linux_nat_async)
-    fprintf_unfiltered (gdb_stdlog,
-                       "LNAE: state(%d): linux_nat_async_events_state(%d), "
-                       "linux_nat_num_queued_events(%d)\n",
-                       state, linux_nat_async_events_state,
-                       linux_nat_num_queued_events);
-
-  if (current_state != state)
-    {
-      sigset_t mask;
-      sigemptyset (&mask);
-      sigaddset (&mask, SIGCHLD);
-
-      /* Always block before changing state.  */
-      sigprocmask (SIG_BLOCK, &mask, NULL);
-
-      /* Set new state.  */
-      linux_nat_async_events_state = state;
-
-      switch (state)
+      else
        {
-       case sigchld_sync:
-         {
-           /* Block target events.  */
-           sigprocmask (SIG_BLOCK, &mask, NULL);
-           sigaction (SIGCHLD, &sync_sigchld_action, NULL);
-           /* Get events out of queue, and make them available to
-              queued_waitpid / my_waitpid.  */
-           pipe_to_local_event_queue ();
-         }
-         break;
-       case sigchld_async:
-         {
-           /* Unblock target events for async mode.  */
-
-           sigprocmask (SIG_BLOCK, &mask, NULL);
+         linux_nat_async_mask_value = new_mask;
 
-           /* Put events we already waited on, in the pipe first, so
-              events are FIFO.  */
-           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 ();
-
-           /* Let'em come.   */
-           sigaction (SIGCHLD, &async_sigchld_action, NULL);
-           sigprocmask (SIG_UNBLOCK, &mask, NULL);
-         }
-         break;
-       case sigchld_default:
-         {
-           /* SIGCHLD default mode.  */
-           sigaction (SIGCHLD, &sigchld_default_action, NULL);
-
-           /* Get events out of queue, and make them available to
-              queued_waitpid / my_waitpid.  */
-           pipe_to_local_event_queue ();
-
-           /* Unblock SIGCHLD.  */
-           sigprocmask (SIG_UNBLOCK, &mask, NULL);
-         }
-         break;
+         /* If we're going out of async-mask in all-stop, then the
+            inferior is stopped.  The next resume will call
+            target_async.  In non-stop, the target event source
+            should be always registered in the event loop.  Do so
+            now.  */
+         if (non_stop)
+           linux_nat_async (inferior_event_handler, 0);
        }
     }
 
-  return current_state;
+  return curr_mask;
 }
 
 static int async_terminal_is_ours = 1;
@@ -4260,7 +4381,7 @@ linux_nat_terminal_inferior (void)
 
 /* target_terminal_ours implementation.  */
 
-void
+static void
 linux_nat_terminal_ours (void)
 {
   if (!target_is_async_p ())
@@ -4290,10 +4411,69 @@ static void (*async_client_callback) (enum inferior_event_type event_type,
                                      void *context);
 static void *async_client_context;
 
+/* SIGCHLD handler that serves two purposes: In non-stop/async mode,
+   so we notice when any child changes state, and notify the
+   event-loop; it allows us to use sigsuspend in linux_nat_wait_1
+   above to wait for the arrival of a SIGCHLD.  */
+
 static void
-linux_nat_async_file_handler (int error, gdb_client_data client_data)
+sigchld_handler (int signo)
+{
+  int old_errno = errno;
+
+  if (debug_linux_nat_async)
+    fprintf_unfiltered (gdb_stdlog, "sigchld\n");
+
+  if (signo == SIGCHLD
+      && linux_nat_event_pipe[0] != -1)
+    async_file_mark (); /* Let the event loop know that there are
+                          events to handle.  */
+
+  errno = old_errno;
+}
+
+/* Callback registered with the target events file descriptor.  */
+
+static void
+handle_target_event (int error, gdb_client_data client_data)
+{
+  (*async_client_callback) (INF_REG_EVENT, async_client_context);
+}
+
+/* Create/destroy the target events pipe.  Returns previous state.  */
+
+static int
+linux_async_pipe (int enable)
 {
-  async_client_callback (INF_REG_EVENT, async_client_context);
+  int previous = (linux_nat_event_pipe[0] != -1);
+
+  if (previous != enable)
+    {
+      sigset_t prev_mask;
+
+      block_child_signals (&prev_mask);
+
+      if (enable)
+       {
+         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
+       {
+         close (linux_nat_event_pipe[0]);
+         close (linux_nat_event_pipe[1]);
+         linux_nat_event_pipe[0] = -1;
+         linux_nat_event_pipe[1] = -1;
+       }
+
+      restore_child_signals_mask (&prev_mask);
+    }
+
+  return previous;
 }
 
 /* target_async implementation.  */
@@ -4310,31 +4490,75 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type,
     {
       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 (sigchld_async);
+      if (!linux_async_pipe (1))
+       {
+         add_file_handler (linux_nat_event_pipe[0],
+                           handle_target_event, NULL);
+         /* There may be pending events to handle.  Tell the event loop
+            to poll them.  */
+         async_file_mark ();
+       }
     }
   else
     {
       async_client_callback = callback;
       async_client_context = context;
-
-      linux_nat_async_events (sigchld_sync);
       delete_file_handler (linux_nat_event_pipe[0]);
+      linux_async_pipe (0);
     }
   return;
 }
 
+/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other
+   event came out.  */
+
 static int
-send_sigint_callback (struct lwp_info *lp, void *data)
+linux_nat_stop_lwp (struct lwp_info *lwp, void *data)
 {
-  /* Use is_running instead of !lp->stopped, because the lwp may be
-     stopped due to an internal event, and we want to interrupt it in
-     that case too.  What we want is to check if the thread is stopped
-     from the point of view of the user.  */
-  if (is_running (lp->ptid))
-    kill_lwp (GET_LWP (lp->ptid), SIGINT);
+  if (!lwp->stopped)
+    {
+      int pid, status;
+      ptid_t ptid = lwp->ptid;
+
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LNSL: running -> suspending %s\n",
+                           target_pid_to_str (lwp->ptid));
+
+
+      stop_callback (lwp, NULL);
+      stop_wait_callback (lwp, NULL);
+
+      /* If the lwp exits while we try to stop it, there's nothing
+        else to do.  */
+      lwp = find_lwp_pid (ptid);
+      if (lwp == NULL)
+       return 0;
+
+      /* If we didn't collect any signal other than SIGSTOP while
+        stopping the LWP, push a SIGNAL_0 event.  In either case, the
+        event-loop will end up calling target_wait which will collect
+        these.  */
+      if (lwp->status == 0)
+       lwp->status = W_STOPCODE (0);
+      async_file_mark ();
+    }
+  else
+    {
+      /* Already known to be stopped; do nothing.  */
+
+      if (debug_linux_nat)
+       {
+         if (find_thread_pid (lwp->ptid)->stop_requested)
+           fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/stop_requested %s\n",
+                               target_pid_to_str (lwp->ptid));
+         else
+           fprintf_unfiltered (gdb_stdlog, "\
+LNSL: already stopped/no stop_requested yet %s\n",
+                               target_pid_to_str (lwp->ptid));
+       }
+    }
   return 0;
 }
 
@@ -4342,19 +4566,25 @@ static void
 linux_nat_stop (ptid_t ptid)
 {
   if (non_stop)
-    {
-      if (ptid_equal (ptid, minus_one_ptid))
-       iterate_over_lwps (send_sigint_callback, &ptid);
-      else
-       {
-         struct lwp_info *lp = find_lwp_pid (ptid);
-         send_sigint_callback (lp, NULL);
-       }
-    }
+    iterate_over_lwps (ptid, linux_nat_stop_lwp, NULL);
   else
     linux_ops->to_stop (ptid);
 }
 
+static void
+linux_nat_close (int quitting)
+{
+  /* Unregister from the event loop.  */
+  if (target_is_async_p ())
+    target_async (NULL, 0);
+
+  /* Reset the async_masking.  */
+  linux_nat_async_mask_value = 1;
+
+  if (linux_ops->to_close)
+    linux_ops->to_close (quitting);
+}
+
 void
 linux_nat_add_target (struct target_ops *t)
 {
@@ -4385,10 +4615,13 @@ linux_nat_add_target (struct target_ops *t)
   t->to_async_mask = linux_nat_async_mask;
   t->to_terminal_inferior = linux_nat_terminal_inferior;
   t->to_terminal_ours = linux_nat_terminal_ours;
+  t->to_close = linux_nat_close;
 
   /* Methods for non-stop support.  */
   t->to_stop = linux_nat_stop;
 
+  t->to_supports_multi_process = linux_nat_supports_multi_process;
+
   /* 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
@@ -4396,10 +4629,6 @@ linux_nat_add_target (struct target_ops *t)
      also want to be used for single-threaded processes.  */
 
   add_target (t);
-
-  /* TODO: Eliminate this and have libthread_db use
-     find_target_beneath.  */
-  thread_db_init (t);
 }
 
 /* Register a method to call whenever a new thread is attached.  */
@@ -4412,6 +4641,19 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
   linux_nat_new_thread = new_thread;
 }
 
+/* Register a method that converts a siginfo object between the layout
+   that ptrace returns, and the layout in the architecture of the
+   inferior.  */
+void
+linux_nat_set_siginfo_fixup (struct target_ops *t,
+                            int (*siginfo_fixup) (struct siginfo *,
+                                                  gdb_byte *,
+                                                  int))
+{
+  /* Save the pointer.  */
+  linux_nat_siginfo_fixup = siginfo_fixup;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
@@ -4423,17 +4665,8 @@ linux_nat_get_siginfo (ptid_t ptid)
   return &lp->siginfo;
 }
 
-/* Enable/Disable async mode.  */
-
-static void
-linux_nat_setup_async (void)
-{
-  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);
-}
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_linux_nat;
 
 void
 _initialize_linux_nat (void)
@@ -4467,38 +4700,22 @@ Enables printf debugging output."),
                            show_debug_linux_nat_async,
                            &setdebuglist, &showdebuglist);
 
-  /* Get the default SIGCHLD action.  Used while forking an inferior
-     (see linux_nat_create_inferior/linux_nat_async_events).  */
-  sigaction (SIGCHLD, NULL, &sigchld_default_action);
-
-  /* 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);
 
-  /* The synchronous SIGCHLD handler.  */
-  sync_sigchld_action.sa_handler = sigchld_handler;
-  sigemptyset (&sync_sigchld_action.sa_mask);
-  sync_sigchld_action.sa_flags = SA_RESTART;
+  /* Install a SIGCHLD handler.  */
+  sigchld_action.sa_handler = sigchld_handler;
+  sigemptyset (&sigchld_action.sa_mask);
+  sigchld_action.sa_flags = SA_RESTART;
 
   /* Make it the default.  */
-  sigaction (SIGCHLD, &sync_sigchld_action, NULL);
+  sigaction (SIGCHLD, &sigchld_action, NULL);
 
   /* Make sure we don't block SIGCHLD during a sigsuspend.  */
   sigprocmask (SIG_SETMASK, NULL, &suspend_mask);
   sigdelset (&suspend_mask, SIGCHLD);
 
-  /* 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;
-
-  linux_nat_setup_async ();
+  sigemptyset (&blocked_mask);
 
   add_setshow_boolean_cmd ("disable-randomization", class_support,
                           &disable_randomization, _("\
@@ -4545,7 +4762,6 @@ lin_thread_get_thread_signals (sigset_t *set)
 {
   struct sigaction action;
   int restart, cancel;
-  sigset_t blocked_mask;
 
   sigemptyset (&blocked_mask);
   sigemptyset (set);
This page took 0.058053 seconds and 4 git commands to generate.