+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>
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. */
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);
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 ();
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 ());
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;
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;
+}
+
\f
/* Non-stop version of target_stop. Uses `vCont;t' to stop a remote
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;
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;
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)
{
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)
{
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
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);