diff options
author | Pedro Alves <palves@redhat.com> | 2020-07-09 11:31:29 +0100 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2020-07-09 12:13:11 +0100 |
commit | a99047e6054300475ece0d5039322854cfb3d5ab (patch) | |
tree | 67964cfa07c32ab3a61459b6cc44a91c6cdd6575 /gdb/thread.c | |
parent | 1ad36a4b892fc4425d6f24c298713eeafece7b04 (diff) | |
download | binutils-users/palves/pr26199-busy-loop-target-events.zip binutils-users/palves/pr26199-busy-loop-target-events.tar.gz binutils-users/palves/pr26199-busy-loop-target-events.tar.bz2 |
Make scoped_restore_current_thread's cdtors exception free (RFC)users/palves/pr26199-busy-loop-target-events
If the remote target closes while we're reading registers/memory for
restoring the selected frame in scoped_restore_current_thread's dtor,
the corresponding TARGET_CLOSE_ERROR error is swallowed by the
scoped_restore_current_thread's dtor, because letting exceptions
escape from a dtor is bad. It isn't great to lose that errors like
that, though. I've been thinking about how to avoid it, and I came up
with this patch.
The idea here is to make scoped_restore_current_thread's dtor do as
little as possible, to avoid any work that might throw in the first
place. And to do that, instead of having the dtor call
restore_selected_frame, which re-finds the previously selected frame,
just record the frame_id/level of the desired selected frame, and have
get_selected_frame find the frame the next time it is called. In
effect, this implements most of Cagney's suggestion, here:
/* On demand, create the selected frame and then return it. If the
selected frame can not be created, this function prints then throws
an error. When MESSAGE is non-NULL, use it for the error message,
otherwize use a generic error message. */
/* FIXME: cagney/2002-11-28: At present, when there is no selected
frame, this function always returns the current (inner most) frame.
It should instead, when a thread has previously had its frame
selected (but not resumed) and the frame cache invalidated, find
and then return that thread's previously selected frame. */
extern struct frame_info *get_selected_frame (const char *message);
The only thing missing to fully implement that would be to make
reinit_frame_cache just clear selected_frame instead of calling
select_frame(NULL), and the call select_frame(NULL) explicitly in the
places where we really wanted reinit_frame_cache to go back to the
current frame too. That can done separately, though, I'm not
proposing to do that in this patch.
Note that this patch renames restore_selected_frame to
lookup_selected_frame, and adds a new restore_selected_frame function
that doesn't throw, to be paired with the also-new save_selected_frame
function.
lookup_selected_frame should really move from thread.c to frame.c, but
I didn't do that here, just to avoid churn in the patch while it
collects comments. I did make it extern and declared it in frame.h
already, preparing for the move. I will do the move as a follow up
patch if people agree with this approach.
Incidentally, this patch alone would fix the crashes fixed by the
previous patches in the series, because with this,
scoped_restore_current_thread's constructor doesn't throw either.
gdb/ChangeLog:
* blockframe.c (block_innermost_frame): Use get_selected_frame.
* frame.c
(scoped_restore_selected_frame::scoped_restore_selected_frame):
Use save_selected_frame. Save language as well.
(scoped_restore_selected_frame::~scoped_restore_selected_frame):
Use restore_selected_frame, and restore language as well.
(selected_frame_id, selected_frame_level): New.
(selected_frame): Update comments.
(save_selected_frame, restore_selected_frame): New.
(get_selected_frame): Use lookup_selected_frame.
(get_selected_frame_if_set): Delete.
(select_frame): Record selected_frame_level and selected_frame_id.
* frame.h (scoped_restore_selected_frame) <m_level, m_lang>: New
fields.
(get_selected_frame_if_set): Delete declaration.
(select_frame): Update comments.
(save_selected_frame, restore_selected_frame)
(lookup_selected_frame): Declare.
* gdbthread.h (scoped_restore_current_thread) <m_lang>: New field.
* stack.c (select_frame_command_core, frame_command_core): Use
get_selected_frame.
* thread.c (restore_selected_frame): Rename to ...
(lookup_selected_frame): ... this and make extern. Select the
current frame if the frame level is -1.
(scoped_restore_current_thread::restore): Also restore the
language.
(scoped_restore_current_thread::~scoped_restore_current_thread):
Don't try/catch.
(scoped_restore_current_thread::scoped_restore_current_thread):
Save the language as well. Use save_selected_frame.
Diffstat (limited to 'gdb/thread.c')
-rw-r--r-- | gdb/thread.c | 67 |
1 files changed, 16 insertions, 51 deletions
diff --git a/gdb/thread.c b/gdb/thread.c index a3c2be7..e748029 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1325,20 +1325,25 @@ switch_to_thread (process_stratum_target *proc_target, ptid_t ptid) switch_to_thread (thr); } -static void -restore_selected_frame (struct frame_id a_frame_id, int frame_level) +/* See frame.h. */ + +void +lookup_selected_frame (struct frame_id a_frame_id, int frame_level) { struct frame_info *frame = NULL; int count; - /* This means there was no selected frame. */ + /* This either means there was no selected frame, or the selected + frame was the innermost (the current frame). */ if (frame_level == -1) { - select_frame (NULL); + select_frame (get_current_frame ()); return; } - gdb_assert (frame_level >= 0); + /* select_frame never saves 0 in SELECTED_FRAME_LEVEL, so we + shouldn't see it here. */ + gdb_assert (frame_level > 0); /* Restore by level first, check if the frame id is the same as expected. If that fails, try restoring by frame id. If that @@ -1409,22 +1414,14 @@ scoped_restore_current_thread::restore () && target_has_stack && target_has_memory) restore_selected_frame (m_selected_frame_id, m_selected_frame_level); + + set_language (m_lang); } scoped_restore_current_thread::~scoped_restore_current_thread () { if (!m_dont_restore) - { - try - { - restore (); - } - catch (const gdb_exception &ex) - { - /* We're in a dtor, there's really nothing else we can do - but swallow the exception. */ - } - } + restore (); if (m_thread != NULL) m_thread->decref (); @@ -1436,47 +1433,15 @@ scoped_restore_current_thread::scoped_restore_current_thread () m_inf = current_inferior (); m_inf->incref (); + m_lang = current_language->la_language; + if (inferior_ptid != null_ptid) { m_thread = inferior_thread (); m_thread->incref (); - struct frame_info *frame; - m_was_stopped = m_thread->state == THREAD_STOPPED; - if (m_was_stopped - && target_has_registers - && target_has_stack - && target_has_memory) - { - /* When processing internal events, there might not be a - selected frame. If we naively call get_selected_frame - here, then we can end up reading debuginfo for the - current frame, but we don't generally need the debuginfo - at this point. */ - frame = get_selected_frame_if_set (); - } - else - frame = NULL; - - try - { - m_selected_frame_id = get_frame_id (frame); - m_selected_frame_level = frame_relative_level (frame); - } - catch (const gdb_exception_error &ex) - { - m_selected_frame_id = null_frame_id; - m_selected_frame_level = -1; - - /* Better let this propagate. */ - if (ex.error == TARGET_CLOSE_ERROR) - { - m_thread->decref (); - m_inf->decref (); - throw; - } - } + save_selected_frame (&m_selected_frame_id, &m_selected_frame_level); } else m_thread = NULL; |