gdb/testsuite: don't use source tree as temporary HOME directory
[binutils-gdb.git] / gdb / infrun.c
index 50340e6edad4c30542c176e43c3589a6d658684d..90bab8d984f5b1bd557e8cb58faf04c17f38a79e 100644 (file)
@@ -426,7 +426,7 @@ follow_fork_inferior (bool follow_child, bool detach_fork)
 Can not resume the parent process over vfork in the foreground while\n\
 holding the child stopped.  Try \"set detach-on-fork\" or \
 \"set schedule-multiple\".\n"));
-      return 1;
+      return true;
     }
 
   if (!follow_child)
@@ -662,7 +662,9 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
       switch_to_thread (child_thr);
     }
 
-  return target_follow_fork (follow_child, detach_fork);
+  target_follow_fork (follow_child, detach_fork);
+
+  return false;
 }
 
 /* Tell the target to follow the fork we're stopped at.  Returns true
@@ -1777,7 +1779,7 @@ displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
   /* Fixup may need to read memory/registers.  Switch to the thread
      that we're fixing up.  Also, target_stopped_by_watchpoint checks
      the current thread, and displaced_step_restore performs ptid-dependent
-     memory accesses using current_inferior() and current_top_target().  */
+     memory accesses using current_inferior().  */
   switch_to_thread (event_thread);
 
   displaced_step_reset_cleanup cleanup (displaced);
@@ -2030,7 +2032,8 @@ set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c)
   if (!target_can_lock_scheduler ())
     {
       scheduler_mode = schedlock_off;
-      error (_("Target '%s' cannot support this command."), target_shortname);
+      error (_("Target '%s' cannot support this command."),
+            target_shortname ());
     }
 }
 
@@ -2172,8 +2175,6 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig)
 
   target_resume (resume_ptid, step, sig);
 
-  target_commit_resume ();
-
   if (target_can_async_p ())
     target_async (1);
 }
@@ -2760,28 +2761,220 @@ schedlock_applies (struct thread_info *tp)
                                            execution_direction)));
 }
 
-/* Calls target_commit_resume on all targets.  */
+/* Set process_stratum_target::COMMIT_RESUMED_STATE in all target
+   stacks that have threads executing and don't have threads with
+   pending events.  */
 
 static void
-commit_resume_all_targets ()
+maybe_set_commit_resumed_all_targets ()
 {
   scoped_restore_current_thread restore_thread;
 
-  /* Map between process_target and a representative inferior.  This
-     is to avoid committing a resume in the same target more than
-     once.  Resumptions must be idempotent, so this is an
-     optimization.  */
-  std::unordered_map<process_stratum_target *, inferior *> conn_inf;
-
   for (inferior *inf : all_non_exited_inferiors ())
-    if (inf->has_execution ())
-      conn_inf[inf->process_target ()] = inf;
+    {
+      process_stratum_target *proc_target = inf->process_target ();
+
+      if (proc_target->commit_resumed_state)
+       {
+         /* We already set this in a previous iteration, via another
+            inferior sharing the process_stratum target.  */
+         continue;
+       }
+
+      /* If the target has no resumed threads, it would be useless to
+        ask it to commit the resumed threads.  */
+      if (!proc_target->threads_executing)
+       {
+         infrun_debug_printf ("not requesting commit-resumed for target "
+                              "%s, no resumed threads",
+                              proc_target->shortname ());
+         continue;
+       }
+
+      /* As an optimization, if a thread from this target has some
+        status to report, handle it before requiring the target to
+        commit its resumed threads: handling the status might lead to
+        resuming more threads.  */
+      bool has_thread_with_pending_status = false;
+      for (thread_info *thread : all_non_exited_threads (proc_target))
+       if (thread->resumed && thread->suspend.waitstatus_pending_p)
+         {
+           has_thread_with_pending_status = true;
+           break;
+         }
+
+      if (has_thread_with_pending_status)
+       {
+         infrun_debug_printf ("not requesting commit-resumed for target %s, a"
+                              " thread has a pending waitstatus",
+                              proc_target->shortname ());
+         continue;
+       }
+
+      switch_to_inferior_no_thread (inf);
+
+      if (target_has_pending_events ())
+       {
+         infrun_debug_printf ("not requesting commit-resumed for target %s, "
+                              "target has pending events",
+                              proc_target->shortname ());
+         continue;
+       }
+
+      infrun_debug_printf ("enabling commit-resumed for target %s",
+                          proc_target->shortname ());
+
+      proc_target->commit_resumed_state = true;
+    }
+}
 
-  for (const auto &ci : conn_inf)
+/* See infrun.h.  */
+
+void
+maybe_call_commit_resumed_all_targets ()
+{
+  scoped_restore_current_thread restore_thread;
+
+  for (inferior *inf : all_non_exited_inferiors ())
     {
-      inferior *inf = ci.second;
+      process_stratum_target *proc_target = inf->process_target ();
+
+      if (!proc_target->commit_resumed_state)
+       continue;
+
       switch_to_inferior_no_thread (inf);
-      target_commit_resume ();
+
+      infrun_debug_printf ("calling commit_resumed for target %s",
+                          proc_target->shortname());
+
+      target_commit_resumed ();
+    }
+}
+
+/* To track nesting of scoped_disable_commit_resumed objects, ensuring
+   that only the outermost one attempts to re-enable
+   commit-resumed.  */
+static bool enable_commit_resumed = true;
+
+/* See infrun.h.  */
+
+scoped_disable_commit_resumed::scoped_disable_commit_resumed
+  (const char *reason)
+  : m_reason (reason),
+    m_prev_enable_commit_resumed (enable_commit_resumed)
+{
+  infrun_debug_printf ("reason=%s", m_reason);
+
+  enable_commit_resumed = false;
+
+  for (inferior *inf : all_non_exited_inferiors ())
+    {
+      process_stratum_target *proc_target = inf->process_target ();
+
+      if (m_prev_enable_commit_resumed)
+       {
+         /* This is the outermost instance: force all
+            COMMIT_RESUMED_STATE to false.  */
+         proc_target->commit_resumed_state = false;
+       }
+      else
+       {
+         /* This is not the outermost instance, we expect
+            COMMIT_RESUMED_STATE to have been cleared by the
+            outermost instance.  */
+         gdb_assert (!proc_target->commit_resumed_state);
+       }
+    }
+}
+
+/* See infrun.h.  */
+
+void
+scoped_disable_commit_resumed::reset ()
+{
+  if (m_reset)
+    return;
+  m_reset = true;
+
+  infrun_debug_printf ("reason=%s", m_reason);
+
+  gdb_assert (!enable_commit_resumed);
+
+  enable_commit_resumed = m_prev_enable_commit_resumed;
+
+  if (m_prev_enable_commit_resumed)
+    {
+      /* This is the outermost instance, re-enable
+         COMMIT_RESUMED_STATE on the targets where it's possible.  */
+      maybe_set_commit_resumed_all_targets ();
+    }
+  else
+    {
+      /* This is not the outermost instance, we expect
+        COMMIT_RESUMED_STATE to still be false.  */
+      for (inferior *inf : all_non_exited_inferiors ())
+       {
+         process_stratum_target *proc_target = inf->process_target ();
+         gdb_assert (!proc_target->commit_resumed_state);
+       }
+    }
+}
+
+/* See infrun.h.  */
+
+scoped_disable_commit_resumed::~scoped_disable_commit_resumed ()
+{
+  reset ();
+}
+
+/* See infrun.h.  */
+
+void
+scoped_disable_commit_resumed::reset_and_commit ()
+{
+  reset ();
+  maybe_call_commit_resumed_all_targets ();
+}
+
+/* See infrun.h.  */
+
+scoped_enable_commit_resumed::scoped_enable_commit_resumed
+  (const char *reason)
+  : m_reason (reason),
+    m_prev_enable_commit_resumed (enable_commit_resumed)
+{
+  infrun_debug_printf ("reason=%s", m_reason);
+
+  if (!enable_commit_resumed)
+    {
+      enable_commit_resumed = true;
+
+      /* Re-enable COMMIT_RESUMED_STATE on the targets where it's
+        possible.  */
+      maybe_set_commit_resumed_all_targets ();
+
+      maybe_call_commit_resumed_all_targets ();
+    }
+}
+
+/* See infrun.h.  */
+
+scoped_enable_commit_resumed::~scoped_enable_commit_resumed ()
+{
+  infrun_debug_printf ("reason=%s", m_reason);
+
+  gdb_assert (enable_commit_resumed);
+
+  enable_commit_resumed = m_prev_enable_commit_resumed;
+
+  if (!enable_commit_resumed)
+    {
+      /* Force all COMMIT_RESUMED_STATE back to false.  */
+      for (inferior *inf : all_non_exited_inferiors ())
+       {
+         process_stratum_target *proc_target = inf->process_target ();
+         proc_target->commit_resumed_state = false;
+       }
     }
 }
 
@@ -3005,7 +3198,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
   cur_thr->prev_pc = regcache_read_pc_protected (regcache);
 
   {
-    scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume ();
+    scoped_disable_commit_resumed disable_commit_resumed ("proceeding");
 
     started = start_step_over ();
 
@@ -3073,9 +3266,9 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
        if (!ecs->wait_some_more)
          error (_("Command aborted."));
       }
-  }
 
-  commit_resume_all_targets ();
+    disable_commit_resumed.reset_and_commit ();
+  }
 
   finish_state.release ();
 
@@ -3877,8 +4070,16 @@ fetch_inferior_event ()
       = make_scoped_restore (&execution_direction,
                             target_execution_direction ());
 
+    /* Allow targets to pause their resumed threads while we handle
+       the event.  */
+    scoped_disable_commit_resumed disable_commit_resumed ("handling event");
+
     if (!do_target_wait (minus_one_ptid, ecs, TARGET_WNOHANG))
-      return;
+      {
+       infrun_debug_printf ("do_target_wait returned no event");
+       disable_commit_resumed.reset_and_commit ();
+       return;
+      }
 
     gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
 
@@ -3969,6 +4170,8 @@ fetch_inferior_event ()
     /* No error, don't finish the thread states yet.  */
     finish_state.release ();
 
+    disable_commit_resumed.reset_and_commit ();
+
     /* This scope is used to ensure that readline callbacks are
        reinstalled here.  */
   }
@@ -4500,12 +4703,11 @@ save_waitstatus (struct thread_info *tp, const target_waitstatus *ws)
   tp->suspend.waitstatus = *ws;
   tp->suspend.waitstatus_pending_p = 1;
 
-  struct regcache *regcache = get_thread_regcache (tp);
-  const address_space *aspace = regcache->aspace ();
-
   if (ws->kind == TARGET_WAITKIND_STOPPED
       && ws->value.sig == GDB_SIGNAL_TRAP)
     {
+      struct regcache *regcache = get_thread_regcache (tp);
+      const address_space *aspace = regcache->aspace ();
       CORE_ADDR pc = regcache_read_pc (regcache);
 
       adjust_pc_after_break (tp, &tp->suspend.waitstatus);
@@ -5812,7 +6014,8 @@ handle_signal_stop (struct execution_control_state *ecs)
 
          infrun_debug_printf ("stopped by watchpoint");
 
-         if (target_stopped_data_address (current_top_target (), &addr))
+         if (target_stopped_data_address (current_inferior ()->top_target (),
+                                          &addr))
            infrun_debug_printf ("stopped data address=%s",
                                 paddress (reg_gdbarch, addr));
          else
@@ -8834,7 +9037,8 @@ siginfo_value_read (struct value *v)
   validate_registers_access ();
 
   transferred =
-    target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO,
+    target_read (current_inferior ()->top_target (),
+                TARGET_OBJECT_SIGNAL_INFO,
                 NULL,
                 value_contents_all_raw (v),
                 value_offset (v),
@@ -8856,7 +9060,7 @@ siginfo_value_write (struct value *v, struct value *fromval)
      vice versa.  */
   validate_registers_access ();
 
-  transferred = target_write (current_top_target (),
+  transferred = target_write (current_inferior ()->top_target (),
                              TARGET_OBJECT_SIGNAL_INFO,
                              NULL,
                              value_contents_all_raw (fromval),
@@ -8920,7 +9124,8 @@ public:
 
        siginfo_data.reset ((gdb_byte *) xmalloc (len));
 
-       if (target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL,
+       if (target_read (current_inferior ()->top_target (),
+                        TARGET_OBJECT_SIGNAL_INFO, NULL,
                         siginfo_data.get (), 0, len) != len)
          {
            /* Errors ignored.  */
@@ -8955,7 +9160,8 @@ public:
        struct type *type = gdbarch_get_siginfo_type (gdbarch);
 
        /* Errors ignored.  */
-       target_write (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL,
+       target_write (current_inferior ()->top_target (),
+                     TARGET_OBJECT_SIGNAL_INFO, NULL,
                      m_siginfo_data.get (), 0, TYPE_LENGTH (type));
       }
 
@@ -9552,11 +9758,13 @@ enabled by default on some platforms."),
   inferior_ptid = null_ptid;
   target_last_wait_ptid = minus_one_ptid;
 
-  gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed);
-  gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested);
-  gdb::observers::thread_exit.attach (infrun_thread_thread_exit);
-  gdb::observers::inferior_exit.attach (infrun_inferior_exit);
-  gdb::observers::inferior_execd.attach (infrun_inferior_execd);
+  gdb::observers::thread_ptid_changed.attach (infrun_thread_ptid_changed,
+                                             "infrun");
+  gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested,
+                                               "infrun");
+  gdb::observers::thread_exit.attach (infrun_thread_thread_exit, "infrun");
+  gdb::observers::inferior_exit.attach (infrun_inferior_exit, "infrun");
+  gdb::observers::inferior_execd.attach (infrun_inferior_execd, "infrun");
 
   /* Explicitly create without lookup, since that tries to create a
      value with a void typed value, and when we get here, gdbarch