[PATCH 3/3] Replace TUI's select_frame hook (PR tui/13378)

Patrick Palka
2015-06-27T02:35:55Z

The select_frame hook is used by TUI to update TUI's frame and register
information following changes to the selected frame. The problem with
this hook is that it gets called after every single frame change, even
if the frame change is only temporary or internal. This is the primary
cause of flickering and slowdown when running the inferior under TUI
with conditional breakpoints set. Internal GDB events are the source of
many calls to select_frame and these internal events are triggered
frequently, especially when a few conditional breakpoints are set.

This patch removes the select_frame hook altogether and instead makes
the frame and register information get updated in two key places (using
observers): after an inferior stops, and right before displaying a
prompt. The latter hook covers the case when frame information must be
updated following a call to "up", "down", "run", "continue" etc and the
former covers the case when frame information must be updated after the
inferior stops in async execution mode. Together these hooks should
cover all the cases when frame information ought to be refreshed (and
when the relevant windows ought to be subsequently updated).

Effectively, with this patch, frame/PC changes that do not immediately
precede an inferior-stop event or a prompt display event no longer cause
TUI's frame and register information to be updated.

And as a result of this change and of the previous change to
tui_show_frame_info, the TUI is much more disciplined about updating the
screen, and so the flicker as described in the PR is totally gone.

gdb/ChangeLog:

* frame.c (select_frame): Remove reference to
deprecated_selected_frame_level_changed_hook.
* frame.h (deprecated_selected_frame_level_changed_hook): Remove
declaration.
* stack.c (deprecated_selected_frame_level_changed_hook):
Likewise.
* tui/tui-hooks.c (tui_selected_frame_level_changed_hook):
Rename to ...
(tui_refresh_frame_and_register_information): ... this. Handle
the case where there is no stack.
(tui_before_prompt): New function.
(tui_before_prompt_observer): New observer.
(tui_install_hooks): Register tui_before_prompt_observer to
call tui_before_prompt. Remove reference to
deprecated_selected_frame_level_changed_hook.
(tui_remove_hooks): Detach and unset tui_before_prompt_observer.
Remove reference to
deprecated_selected_frame_level_changed_hook.
* tui/tui-hooks.h (tui_refresh_frame_and_register_information):
Export.
* tui/tui-interp.c: Include "tui/tui-hooks.h".
(tui_on_sync_execution_done): Call
tui_refresh_frame_and_register_information if tui_active.
---
gdb/frame.c | 2 --
gdb/frame.h | 2 --
gdb/stack.c | 2 --
gdb/tui/tui-hooks.c | 64 ++++++++++++++++++++++++++++++----------------------
gdb/tui/tui-hooks.h | 5 ++++
gdb/tui/tui-interp.c | 4 ++++
6 files changed, 46 insertions(+), 33 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index b3cbf23..da5bfb9 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1576,8 +1576,6 @@ select_frame (struct frame_info *fi)
selected_frame = fi;
/* NOTE: cagney/2002-05-04: FI can be NULL. This occurs when the
frame is being invalidated. */
- if (deprecated_selected_frame_level_changed_hook)
- deprecated_selected_frame_level_changed_hook (frame_relative_level (fi));

/* FIXME: kseitz/2002-08-28: It would be nice to call
selected_frame_level_changed_event() right here, but due to limitations
diff --git a/gdb/frame.h b/gdb/frame.h
index 53a93e0..be64c57 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -763,8 +763,6 @@ extern void args_info (char *, int);

extern void locals_info (char *, int);

-extern void (*deprecated_selected_frame_level_changed_hook) (int);
-
extern void return_command (char *, int);

/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
diff --git a/gdb/stack.c b/gdb/stack.c
index eea575a..39803d9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -52,8 +52,6 @@
#include "symfile.h"
#include "extension.h"

-void (*deprecated_selected_frame_level_changed_hook) (int);
-
/* The possible choices of "set print frame-arguments", and the value
of this setting. */

diff --git a/gdb/tui/tui-hooks.c b/gdb/tui/tui-hooks.c
index 8d84551..a0994c4 100644
--- a/gdb/tui/tui-hooks.c
+++ b/gdb/tui/tui-hooks.c
@@ -119,46 +119,46 @@ tui_about_to_proceed (void)
tui_target_has_run = 1;
}

-/* The selected frame has changed. This is happens after a target
- stop or when the user explicitly changes the frame
- (up/down/thread/...). */
-static void
-tui_selected_frame_level_changed_hook (int level)
+/* See tui-hooks.h. */
+
+void
+tui_refresh_frame_and_register_information (void)
{
struct frame_info *fi;
CORE_ADDR pc;
struct cleanup *old_chain;

- /* Negative level means that the selected frame was cleared. */
- if (level < 0)
- return;
-
old_chain = make_cleanup_restore_target_terminal ();
target_terminal_ours_for_output ();

- fi = get_selected_frame (NULL);
- /* Ensure that symbols for this frame are read in. Also, determine
- the source language of this frame, and switch to it if
- desired. */
- if (get_frame_pc_if_available (fi, &pc))
+ if (has_stack_frames ())
{
- struct symtab *s;
-
- s = find_pc_line_symtab (pc);
- /* elz: This if here fixes the problem with the pc not being
- displayed in the tui asm layout, with no debug symbols. The
- value of s would be 0 here, and select_source_symtab would
- abort the command by calling the 'error' function. */
- if (s)
- select_source_symtab (s);
+ fi = get_selected_frame (NULL);
+ /* Ensure that symbols for this frame are read in. Also, determine
+ the source language of this frame, and switch to it if
+ desired. */
+ if (get_frame_pc_if_available (fi, &pc))
+ {
+ struct symtab *s;
+
+ s = find_pc_line_symtab (pc);
+ /* elz: This if here fixes the problem with the pc not being
+ displayed in the tui asm layout, with no debug symbols. The
+ value of s would be 0 here, and select_source_symtab would
+ abort the command by calling the 'error' function. */
+ if (s)
+ select_source_symtab (s);
+ }
}
+ else
+ fi = NULL;

/* Display the frame position (even if there is no symbols or the PC
is not known). */
tui_show_frame_info (fi);

/* Refresh the register window if it's visible. */
- if (tui_is_window_visible (DATA_WIN))
+ if (fi != NULL && tui_is_window_visible (DATA_WIN))
{
tui_refreshing_registers = 1;
tui_check_data_values (fi);
@@ -191,19 +191,26 @@ tui_inferior_exit (struct inferior *inf)
tui_display_main ();
}

+/* Observer for the before_prompt notification. */
+
+static void
+tui_before_prompt (const char *current_gdb_prompt)
+{
+ tui_refresh_frame_and_register_information ();
+}
+
/* Observers created when installing TUI hooks. */
static struct observer *tui_bp_created_observer;
static struct observer *tui_bp_deleted_observer;
static struct observer *tui_bp_modified_observer;
static struct observer *tui_inferior_exit_observer;
static struct observer *tui_about_to_proceed_observer;
+static struct observer *tui_before_prompt_observer;

/* Install the TUI specific hooks. */
void
tui_install_hooks (void)
{
- deprecated_selected_frame_level_changed_hook
- = tui_selected_frame_level_changed_hook;
deprecated_print_frame_info_listing_hook
= tui_print_frame_info_listing_hook;

@@ -218,6 +225,8 @@ tui_install_hooks (void)
= observer_attach_inferior_exit (tui_inferior_exit);
tui_about_to_proceed_observer
= observer_attach_about_to_proceed (tui_about_to_proceed);
+ tui_before_prompt_observer
+ = observer_attach_before_prompt (tui_before_prompt);

deprecated_register_changed_hook = tui_register_changed_hook;
}
@@ -226,7 +235,6 @@ tui_install_hooks (void)
void
tui_remove_hooks (void)
{
- deprecated_selected_frame_level_changed_hook = 0;
deprecated_print_frame_info_listing_hook = 0;
deprecated_query_hook = 0;
deprecated_register_changed_hook = 0;
@@ -242,6 +250,8 @@ tui_remove_hooks (void)
tui_inferior_exit_observer = NULL;
observer_detach_about_to_proceed (tui_about_to_proceed_observer);
tui_about_to_proceed_observer = NULL;
+ observer_detach_before_prompt (tui_before_prompt_observer);
+ tui_before_prompt_observer = NULL;
}

void _initialize_tui_hooks (void);
diff --git a/gdb/tui/tui-hooks.h b/gdb/tui/tui-hooks.h
index ab6afc9..303d9bb 100644
--- a/gdb/tui/tui-hooks.h
+++ b/gdb/tui/tui-hooks.h
@@ -20,6 +20,11 @@
#ifndef TUI_HOOKS_H
#define TUI_HOOKS_H

+/* Refresh TUI's frame and register information. This is a hook intended to be
+ used to update the screen after potential frame and register changes. */
+
+extern void tui_refresh_frame_and_register_information (void);
+
extern void tui_install_hooks (void);
extern void tui_remove_hooks (void);

diff --git a/gdb/tui/tui-interp.c b/gdb/tui/tui-interp.c
index 1a5639d..4284037 100644
--- a/gdb/tui/tui-interp.c
+++ b/gdb/tui/tui-interp.c
@@ -27,6 +27,7 @@
#include "tui/tui-data.h"
#include "readline/readline.h"
#include "tui/tui-win.h"
+#include "tui/tui-hooks.h"
#include "tui/tui.h"
#include "tui/tui-io.h"
#include "infrun.h"
@@ -107,6 +108,9 @@ tui_on_sync_execution_done (void)
{
if (!interp_quiet_p (tui_interp))
display_gdb_prompt (NULL);
+
+ if (tui_active)
+ tui_refresh_frame_and_register_information ();
}

/* Observer for the command_error notification. */
--
2.5.0.rc0.5.g91e10c5.dirty