aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog15
-rw-r--r--gdb/async-event.c8
-rw-r--r--gdb/async-event.h3
-rw-r--r--gdb/infrun.c12
-rw-r--r--gdb/remote.c21
-rw-r--r--gdb/target-delegates.c27
-rw-r--r--gdb/target.c8
-rw-r--r--gdb/target.h14
8 files changed, 108 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e3ae1c4..fa4d5b7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,6 +1,21 @@
2021-03-26 Simon Marchi <simon.marchi@efficios.com>
Pedro Alves <pedro@palves.net>
+ * async-event.c: Include "infrun.h".
+ (async_event_handler_marked): New.
+ * async-event.h (async_event_handler_marked): Declare.
+ * infrun.c (maybe_set_commit_resumed_all_targets): Switch to
+ inferior before calling target method. Don't commit-resumed if
+ target_has_pending_events is true.
+ * remote.c (remote_target::has_pending_events): New.
+ * target-delegates.c: Regenerate.
+ * target.c (target_has_pending_events): New.
+ * target.h (target_ops::has_pending_events): New target method.
+ (target_has_pending_events): New.
+
+2021-03-26 Simon Marchi <simon.marchi@efficios.com>
+ Pedro Alves <pedro@palves.net>
+
* infcmd.c (run_command_1, attach_command, detach_command)
(interrupt_target_1): Use scoped_disable_commit_resumed.
* infrun.c (do_target_resume): Remove
diff --git a/gdb/async-event.c b/gdb/async-event.c
index c4ab731..7b1abfe 100644
--- a/gdb/async-event.c
+++ b/gdb/async-event.c
@@ -308,6 +308,14 @@ clear_async_event_handler (async_event_handler *async_handler_ptr)
async_handler_ptr->ready = 0;
}
+/* See event-loop.h. */
+
+bool
+async_event_handler_marked (async_event_handler *handler)
+{
+ return handler->ready;
+}
+
/* Check if asynchronous event handlers are ready, and call the
handler function for one that is. */
diff --git a/gdb/async-event.h b/gdb/async-event.h
index 9d96235..47759d5 100644
--- a/gdb/async-event.h
+++ b/gdb/async-event.h
@@ -78,6 +78,9 @@ extern void
loop. */
extern void mark_async_event_handler (struct async_event_handler *handler);
+/* Return true if HANDLER is marked. */
+extern bool async_event_handler_marked (async_event_handler *handler);
+
/* Mark the handler (ASYNC_HANDLER_PTR) as NOT ready. */
extern void clear_async_event_handler (struct async_event_handler *handler);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 347eefb..6176fa9 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2766,6 +2766,8 @@ schedlock_applies (struct thread_info *tp)
static void
maybe_set_commit_resumed_all_targets ()
{
+ scoped_restore_current_thread restore_thread;
+
for (inferior *inf : all_non_exited_inferiors ())
{
process_stratum_target *proc_target = inf->process_target ();
@@ -2807,6 +2809,16 @@ maybe_set_commit_resumed_all_targets ()
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 ());
diff --git a/gdb/remote.c b/gdb/remote.c
index 1036ffd..fd0ad9c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -429,6 +429,7 @@ public:
void commit_resumed () override;
void resume (ptid_t, int, enum gdb_signal) override;
ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
+ bool has_pending_events () override;
void fetch_registers (struct regcache *, int) override;
void store_registers (struct regcache *, int) override;
@@ -6820,6 +6821,26 @@ remote_target::commit_resumed ()
vcont_builder.flush ();
}
+/* Implementation of target_has_pending_events. */
+
+bool
+remote_target::has_pending_events ()
+{
+ if (target_can_async_p ())
+ {
+ remote_state *rs = get_remote_state ();
+
+ if (async_event_handler_marked (rs->remote_async_inferior_event_token))
+ return true;
+
+ /* Note that BUFCNT can be negative, indicating sticky
+ error. */
+ if (rs->remote_desc->bufcnt != 0)
+ return true;
+ }
+ return false;
+}
+
/* Non-stop version of target_stop. Uses `vCont;t' to stop a remote
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index efbb31b..cc8c64a 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -84,6 +84,7 @@ struct dummy_target : public target_ops
bool is_async_p () override;
void async (int arg0) override;
int async_wait_fd () override;
+ bool has_pending_events () override;
void thread_events (int arg0) override;
bool supports_non_stop () override;
bool always_non_stop_p () override;
@@ -258,6 +259,7 @@ struct debug_target : public target_ops
bool is_async_p () override;
void async (int arg0) override;
int async_wait_fd () override;
+ bool has_pending_events () override;
void thread_events (int arg0) override;
bool supports_non_stop () override;
bool always_non_stop_p () override;
@@ -2199,6 +2201,31 @@ debug_target::async_wait_fd ()
return result;
}
+bool
+target_ops::has_pending_events ()
+{
+ return this->beneath ()->has_pending_events ();
+}
+
+bool
+dummy_target::has_pending_events ()
+{
+ return false;
+}
+
+bool
+debug_target::has_pending_events ()
+{
+ bool result;
+ fprintf_unfiltered (gdb_stdlog, "-> %s->has_pending_events (...)\n", this->beneath ()->shortname ());
+ result = this->beneath ()->has_pending_events ();
+ fprintf_unfiltered (gdb_stdlog, "<- %s->has_pending_events (", this->beneath ()->shortname ());
+ fputs_unfiltered (") = ", gdb_stdlog);
+ target_debug_print_bool (result);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ return result;
+}
+
void
target_ops::thread_events (int arg0)
{
diff --git a/gdb/target.c b/gdb/target.c
index 0da035e..995e7ef 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -2679,6 +2679,14 @@ target_commit_resumed ()
current_inferior ()->top_target ()->commit_resumed ();
}
+/* See target.h. */
+
+bool
+target_has_pending_events ()
+{
+ return current_inferior ()->top_target ()->has_pending_events ();
+}
+
void
target_pass_signals (gdb::array_view<const unsigned char> pass_signals)
{
diff --git a/gdb/target.h b/gdb/target.h
index 0aef372..adae49d 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -719,6 +719,15 @@ struct target_ops
TARGET_DEFAULT_NORETURN (tcomplain ());
virtual int async_wait_fd ()
TARGET_DEFAULT_NORETURN (noprocess ());
+ /* Return true if the target has pending events to report to the
+ core. If true, then GDB avoids resuming the target until all
+ pending events are consumed, so that multiple resumptions can
+ be coalesced as an optimization. Most targets can't tell
+ whether they have pending events without calling target_wait,
+ so we default to returning false. The only downside is that a
+ potential optimization is missed. */
+ virtual bool has_pending_events ()
+ TARGET_DEFAULT_RETURN (false);
virtual void thread_events (int)
TARGET_DEFAULT_IGNORE ();
/* This method must be implemented in some situations. See the
@@ -1485,6 +1494,11 @@ extern ptid_t default_target_wait (struct target_ops *ops,
struct target_waitstatus *status,
target_wait_flags options);
+/* Return true if the target has pending events to report to the core.
+ See target_ops::has_pending_events(). */
+
+extern bool target_has_pending_events ();
+
/* Fetch at least register REGNO, or all regs if regno == -1. No result. */
extern void target_fetch_registers (struct regcache *regcache, int regno);