diff options
-rw-r--r-- | gdb/cli-out.c | 172 | ||||
-rw-r--r-- | gdb/cli-out.h | 35 | ||||
-rw-r--r-- | gdb/debuginfod-support.c | 128 | ||||
-rw-r--r-- | gdb/mi/mi-out.c | 24 | ||||
-rw-r--r-- | gdb/mi/mi-out.h | 20 | ||||
-rw-r--r-- | gdb/ui-out.h | 51 |
6 files changed, 279 insertions, 151 deletions
diff --git a/gdb/cli-out.c b/gdb/cli-out.c index e0802df352b..51531d9eda2 100644 --- a/gdb/cli-out.c +++ b/gdb/cli-out.c @@ -262,105 +262,143 @@ cli_ui_out::do_redirect (ui_file *outstream) m_streams.pop_back (); } -/* The cli_ui_out::do_progress_* functions result in the following: - - printed for tty, SHOULD_PRINT == true: - <NAME - [##### ]\r> - - printed for tty, SHOULD_PRINT == false: - <> +void +cli_ui_out::do_progress_start () +{ + cli_progress_info info; + + info.pos = 0; + info.state = progress_update::START; + m_progress_info.push_back (std::move (info)); +} + +/* Pick a reasonable limit for the progress update length. */ +#define MAX_CHARS_PER_LINE 4096 + +/* Print a progress update. MSG is a string to be printed before + If HOWMUCH is between 0.0 and 1.0, a progress bar is displayed + indicating the percentage of completion. If HOWMUCH is negative, + a progress indicator ticks across the screen. Multiple calls + to this function progressively update the display. + + - printed for tty, HOWMUCH between 0.0 and 1.0: + <NAME + [######## ]\r> + - printed for tty, HOWMUCH < 0.0: + <NAME + [ ### ]\r> - printed for not-a-tty: <NAME... > */ void -cli_ui_out::do_progress_start (const std::string &name, bool should_print) +cli_ui_out::do_progress_notify (const std::string &msg, double howmuch) { struct ui_file *stream = m_streams.back (); - cli_progress_info meter; + cli_progress_info &info (m_progress_info.back ()); + + if (info.state == progress_update::START) + { + if (!stream->isatty ()) + { + gdb_printf (stream, "%s...\n", msg.c_str ()); + info.state = progress_update::WORKING; + } + else + { + gdb_printf (stream, "%s\n", msg.c_str ()); + info.state = progress_update::BAR; + } + } + + int chars_per_line = get_chars_per_line (); + if (chars_per_line > MAX_CHARS_PER_LINE) + chars_per_line = MAX_CHARS_PER_LINE; + + if (chars_per_line <= 0 + || info.state == progress_update::WORKING + || !stream->isatty ()) + return; - meter.last_value = 0; - meter.name = name; - if (!stream->isatty ()) + if (howmuch >= 0) { - gdb_printf (stream, "%s...", meter.name.c_str ()); + int width = chars_per_line - 3; + int max = width * howmuch; + + gdb_printf (stream, "\r["); + for (int i = 0; i < width; ++i) + gdb_printf (stream, i < max ? "#" : " "); + gdb_printf (stream, "]"); gdb_flush (stream); - meter.printing = WORKING; } else { - /* Don't actually emit anything until the first call notifies us - of progress. This makes it so a second progress message can - be started before the first one has been notified, without - messy output. */ - meter.printing = should_print ? START : NO_PRINT; + using namespace std::chrono; + milliseconds diff = duration_cast<milliseconds> + (steady_clock::now () - info.last_update); + + /* Advance the progress indicator at a rate of 1 tick every + every 0.5 seconds. */ + if (diff.count () >= 500) + { + int width = chars_per_line - 3; + + gdb_printf (stream, "\r["); + + for (int i = 0; i < width; ++i) + { + if (i >= info.pos % width + && i < (info.pos + 3) % width) + gdb_printf (stream, "#"); + else + gdb_printf (stream, " "); + } + + gdb_printf (stream, "]"); + gdb_flush (stream); + info.last_update = steady_clock::now (); + info.pos++; + } } - m_meters.push_back (std::move (meter)); + return; } +/* Clear the current line of the most recent progress update. Overwrites + the current line with whitespace. */ + void -cli_ui_out::do_progress_notify (double howmuch) +cli_ui_out::clear_current_line () { struct ui_file *stream = m_streams.back (); - cli_progress_info &meter (m_meters.back ()); - - if (meter.printing == NO_PRINT) - return; + int chars_per_line = get_chars_per_line (); - if (meter.printing == START) - { - gdb_printf (stream, "%s\n", meter.name.c_str ()); - gdb_flush (stream); - meter.printing = WORKING; - } + if (chars_per_line <= 0 + || chars_per_line > MAX_CHARS_PER_LINE) + chars_per_line = MAX_CHARS_PER_LINE; - if (meter.printing == WORKING && howmuch >= 1.0) - return; + int width = chars_per_line; - if (!stream->isatty ()) - return; + gdb_printf (stream, "\r"); + for (int i = 0; i < width; ++i) + gdb_printf (stream, " "); + gdb_printf (stream, "\r"); - int chars_per_line = get_chars_per_line (); - if (chars_per_line > 0) - { - int i, max; - int width = chars_per_line - 3; - - max = width * howmuch; - gdb_printf (stream, "\r["); - for (i = 0; i < width; ++i) - gdb_printf (stream, i < max ? "#" : " "); - gdb_printf (stream, "]"); - gdb_flush (stream); - meter.printing = PROGRESS; - } + gdb_flush (stream); } +/* Remove the most recent progress update from the stack and + overwrite the current line with whitespace. */ + void cli_ui_out::do_progress_end () { struct ui_file *stream = m_streams.back (); - cli_progress_info &meter = m_meters.back (); - - if (!stream->isatty ()) - { - gdb_printf (stream, "\n"); - gdb_flush (stream); - } - else if (meter.printing == PROGRESS) - { - int i; - int width = get_chars_per_line () - 3; - - gdb_printf (stream, "\r"); - for (i = 0; i < width + 2; ++i) - gdb_printf (stream, " "); - gdb_printf (stream, "\r"); - gdb_flush (stream); - } + m_progress_info.pop_back (); - m_meters.pop_back (); + if (stream->isatty ()) + clear_current_line (); } /* local functions */ diff --git a/gdb/cli-out.h b/gdb/cli-out.h index 3fc794b61a4..62531ce818d 100644 --- a/gdb/cli-out.h +++ b/gdb/cli-out.h @@ -21,6 +21,7 @@ #define CLI_OUT_H #include "ui-out.h" +#include <chrono> #include <vector> class cli_ui_out : public ui_out @@ -71,8 +72,8 @@ protected: virtual void do_flush () override; virtual void do_redirect (struct ui_file *outstream) override; - virtual void do_progress_start (const std::string &, bool) override; - virtual void do_progress_notify (double) override; + virtual void do_progress_start () override; + virtual void do_progress_notify (const std::string &, double) override; virtual void do_progress_end () override; bool suppress_output () @@ -85,32 +86,20 @@ private: std::vector<ui_file *> m_streams; bool m_suppress_output; - /* Represents the printing state of a progress meter. */ - enum meter_state - { - /* Printing will start with the next output. */ - START, - /* Printing has already started. */ - WORKING, - /* Progress printing has already started. */ - PROGRESS, - /* Printing should not be done. */ - NO_PRINT - }; - - /* The state of a recent progress meter. */ + /* The state of a recent progress update. */ struct cli_progress_info { + /* Position of indicator. */ + int pos; /* The current state. */ - enum meter_state printing; - /* The name to print. */ - std::string name; - /* The last notification value. */ - double last_value; + progress_update::state state; + /* Time of last spinner update. */ + std::chrono::steady_clock::time_point last_update; }; - /* Stack of progress meters. */ - std::vector<cli_progress_info> m_meters; + /* Stack of progress info. */ + std::vector<cli_progress_info> m_progress_info; + void clear_current_line (); }; extern cli_ui_out *cli_out_new (struct ui_file *stream); diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c index f2a31ea1952..92aca018954 100644 --- a/gdb/debuginfod-support.c +++ b/gdb/debuginfod-support.c @@ -24,7 +24,9 @@ #include "gdbsupport/gdb_optional.h" #include "cli/cli-cmds.h" #include "cli/cli-style.h" +#include "cli-out.h" #include "target.h" +#include <sstream> /* Set/show debuginfod commands. */ static cmd_list_element *set_debuginfod_prefix_list; @@ -87,12 +89,12 @@ debuginfod_exec_query (const unsigned char *build_id, struct user_data { user_data (const char *desc, const char *fname) - : desc (desc), fname (fname), has_printed (false) + : desc (desc), fname (fname) { } const char * const desc; - const char * const fname; - bool has_printed; + const char * fname; + ui_out::progress_update progress; }; /* Deleter for a debuginfod_client. */ @@ -108,47 +110,70 @@ struct debuginfod_client_deleter using debuginfod_client_up = std::unique_ptr<debuginfod_client, debuginfod_client_deleter>; +/* Convert SIZE into a unit suitable for use with progress updates. + SIZE should in given in bytes and will be converted into KB or MB. + UNIT will be set to "KB" or "MB" accordingly. */ + +static void +get_size_and_unit (double *size, const char **unit) +{ + *size /= 1024; + + /* If size is greater than 0.01 MB then set unit to MB. */ + if (*size > 10.24) + { + *size /= 1024; + *unit = "MB"; + } + else + *unit = "KB"; +} + static int progressfn (debuginfod_client *c, long cur, long total) { user_data *data = static_cast<user_data *> (debuginfod_get_user_data (c)); gdb_assert (data != nullptr); + string_file styled_fname (current_uiout->can_emit_style_escape ()); + fprintf_styled (&styled_fname, file_name_style.style (), "%s", + data->fname); + if (check_quit_flag ()) { + current_uiout->do_progress_end (); ///? + gdb_printf ("Cancelling download of %s %ps...\n", - data->desc, - styled_string (file_name_style.style (), data->fname)); + data->desc, styled_fname.c_str ()); return 1; } - if (!data->has_printed) + if (debuginfod_verbose == 0) + return 0; + + /* Print progress update. Include the transfer size if available. */ + if (total > 0) { - /* Include the transfer size, if available. */ - if (total > 0) + /* Transfer size is known. */ + double howmuch = (double) cur / (double) total; + + if (howmuch >= 0.0 && howmuch <= 1.0) { - float size = 1.0f * total / 1024; - const char *unit = "KB"; - - /* If size is greater than 0.01 MB, set unit to MB. */ - if (size > 10.24) - { - size /= 1024; - unit = "MB"; - } - - gdb_printf ("Downloading %.2f %s %s %ps...\n", - size, unit, data->desc, - styled_string (file_name_style.style (), - data->fname)); + double size = (double) total; + const char *unit = ""; + + get_size_and_unit (&size, &unit); + std::string msg = string_printf ("Downloading %0.2f %s %s %s\n", + size, unit, data->desc, + styled_fname.c_str ()); + current_uiout->update_progress (msg, howmuch); + return 0; } - else - gdb_printf ("Downloading %s %ps...\n", data->desc, - styled_string (file_name_style.style (), data->fname)); - - data->has_printed = true; } + std::string msg = string_printf ("Downloading %s %s\n", + data->desc, styled_fname.c_str ()); + current_uiout->update_progress (msg, -1); return 0; } @@ -233,6 +258,43 @@ debuginfod_is_enabled () return true; } +/* Print the result of the most recent attempted download. */ + +static void +print_outcome (user_data &data, int fd) +{ + /* Clears the current line of progress output. */ + current_uiout->do_progress_end (); + + string_file styled_fname (current_uiout->can_emit_style_escape ()); + fprintf_styled (&styled_fname, file_name_style.style (), "%s", + data.fname); + + if (debuginfod_verbose > 1 && fd >= 0) + { + struct stat s; + + if (fstat (fd, &s) == 0) + { + double size = (double)s.st_size; + const char *unit = ""; + + get_size_and_unit (&size, &unit); + gdb_printf (_("Retrieved %.02f %s %s %s\n"), size, unit, + data.desc, styled_fname.c_str ()); + } + else + warning (_("Retrieved %s %s but size cannot be read: %s\n"), + data.desc, styled_fname.c_str (), + safe_strerror (errno)); + } + else if (fd < 0 && fd != -ENOENT) + gdb_printf (_("Download failed: %s. " \ + "Continuing without %s %s.\n"), + safe_strerror (-fd), data.desc, + styled_fname.c_str ()); +} + /* See debuginfod-support.h */ scoped_fd @@ -266,11 +328,7 @@ debuginfod_source_query (const unsigned char *build_id, srcpath, &dname)); debuginfod_set_user_data (c, nullptr); - - if (fd.get () < 0 && fd.get () != -ENOENT) - gdb_printf (_("Download failed: %s. Continuing without source file %ps.\n"), - safe_strerror (-fd.get ()), - styled_string (file_name_style.style (), srcpath)); + print_outcome (data, fd.get ()); if (fd.get () >= 0) destname->reset (dname); @@ -308,11 +366,7 @@ debuginfod_debuginfo_query (const unsigned char *build_id, scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len, &dname)); debuginfod_set_user_data (c, nullptr); - - if (fd.get () < 0 && fd.get () != -ENOENT) - gdb_printf (_("Download failed: %s. Continuing without debug info for %ps.\n"), - safe_strerror (-fd.get ()), - styled_string (file_name_style.style (), filename)); + print_outcome (data, fd.get ()); if (fd.get () >= 0) destname->reset (dname); diff --git a/gdb/mi/mi-out.c b/gdb/mi/mi-out.c index 567ef83de9b..6b3e932ffa4 100644 --- a/gdb/mi/mi-out.c +++ b/gdb/mi/mi-out.c @@ -258,6 +258,30 @@ mi_ui_out::main_stream () return (string_file *) m_streams.back (); } +void +mi_ui_out::do_progress_start () +{ + mi_progress_info info; + + info.state = progress_update::START; + m_progress_info.push_back (std::move (info)); +} + +/* Indicate that a task described by NAME is in progress. */ + +void +mi_ui_out::do_progress_notify (const std::string &msg, double howmuch) +{ + mi_progress_info &info (m_progress_info.back ()); + + if (info.state == progress_update::START) + { + struct ui_file *stream = gdb_stdout; + gdb_printf (stream, "%s\n", msg.c_str ()); + info.state = progress_update::WORKING; + } +} + /* Clear the buffer. */ void diff --git a/gdb/mi/mi-out.h b/gdb/mi/mi-out.h index 8f2f2d82ec0..1cc1cc1f74e 100644 --- a/gdb/mi/mi-out.h +++ b/gdb/mi/mi-out.h @@ -25,7 +25,6 @@ struct ui_out; struct ui_file; - class mi_ui_out : public ui_out { public: @@ -83,13 +82,8 @@ protected: virtual bool do_is_mi_like_p () const override { return true; } - virtual void do_progress_start (const std::string &, bool) override - { - } - - virtual void do_progress_notify (double) override - { - } + virtual void do_progress_start () override; + virtual void do_progress_notify (const std::string &, double) override; virtual void do_progress_end () override { @@ -101,6 +95,16 @@ private: void open (const char *name, ui_out_type type); void close (ui_out_type type); + /* The state of a recent progress_update. */ + struct mi_progress_info + { + /* The current state. */ + progress_update::state state; + }; + + /* Stack of progress info. */ + std::vector<mi_progress_info> m_progress_info; + /* Convenience method that returns the MI out's string stream cast to its appropriate type. Assumes/asserts that output was not redirected. */ diff --git a/gdb/ui-out.h b/gdb/ui-out.h index 9e6ff9a29bf..21e7a2bfbe7 100644 --- a/gdb/ui-out.h +++ b/gdb/ui-out.h @@ -277,32 +277,43 @@ class ui_out escapes. */ virtual bool can_emit_style_escape () const = 0; - /* An object that starts and finishes a progress meter. */ - class progress_meter + /* An object that starts and finishes displaying progress updates. */ + class progress_update { public: + /* Represents the printing state of a progress update. */ + enum state + { + /* Printing will start with the next update. */ + START, + /* Printing has already started. */ + WORKING, + /* Progress bar printing has already started. */ + BAR, + /* Printing should not be done. */ + NO_PRINT + }; + /* SHOULD_PRINT indicates whether something should be printed for a tty. */ - progress_meter (struct ui_out *uiout, const std::string &name, - bool should_print) - : m_uiout (uiout) + progress_update () { - m_uiout->do_progress_start (name, should_print); + m_uiout = current_uiout; + m_uiout->do_progress_start (); } - ~progress_meter () + ~progress_update () { - m_uiout->do_progress_notify (1.0); - m_uiout->do_progress_end (); + } - progress_meter (const progress_meter &) = delete; - progress_meter &operator= (const progress_meter &) = delete; + progress_update (const progress_update &) = delete; + progress_update &operator= (const progress_update &) = delete; /* Emit some progress for this progress meter. HOWMUCH may range from 0.0 to 1.0. */ - void progress (double howmuch) + void progress (const std::string& msg, double howmuch) { - m_uiout->do_progress_notify (howmuch); + m_uiout->do_progress_notify (msg, howmuch); } private: @@ -310,6 +321,15 @@ class ui_out struct ui_out *m_uiout; }; + /* Emit some progress corresponding to the most recently created + progress_update object. */ + void update_progress (std::string &msg, double howmuch) + { + do_progress_notify (msg, howmuch); + } + + virtual void do_progress_end () = 0; + protected: virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) @@ -344,9 +364,8 @@ class ui_out virtual void do_flush () = 0; virtual void do_redirect (struct ui_file *outstream) = 0; - virtual void do_progress_start (const std::string &, bool) = 0; - virtual void do_progress_notify (double) = 0; - virtual void do_progress_end () = 0; + virtual void do_progress_start () = 0; + virtual void do_progress_notify (const std::string &, double) = 0; /* Set as not MI-like by default. It is overridden in subclasses if necessary. */ |