summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/cli-out.c172
-rw-r--r--gdb/cli-out.h35
-rw-r--r--gdb/debuginfod-support.c128
-rw-r--r--gdb/mi/mi-out.c24
-rw-r--r--gdb/mi/mi-out.h20
-rw-r--r--gdb/ui-out.h51
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. */