diff options
-rw-r--r-- | gdb/ChangeLog | 15 | ||||
-rw-r--r-- | gdb/async-event.c | 8 | ||||
-rw-r--r-- | gdb/async-event.h | 3 | ||||
-rw-r--r-- | gdb/infrun.c | 12 | ||||
-rw-r--r-- | gdb/remote.c | 21 | ||||
-rw-r--r-- | gdb/target-delegates.c | 27 | ||||
-rw-r--r-- | gdb/target.c | 8 | ||||
-rw-r--r-- | gdb/target.h | 14 |
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); |