Skip to content

Commit

Permalink
Merge branch 'ab/only-single-progress-at-once' into seen
Browse files Browse the repository at this point in the history
* ab/only-single-progress-at-once:
  progress.c: add & assert a "global_progress" variable
  pack-bitmap-write.c: add a missing stop_progress()
  progress.c: add temporary variable from progress struct
  progress.c: stop eagerly fflush(stderr) when not a terminal
  progress.c: call progress_interval() from progress_test_force_update()
  progress.c: move signal handler functions lower
  progress.c tests: test some invalid usage
  progress.c tests: make start/stop verbs on stdin
  • Loading branch information
gitster committed Jul 26, 2021
2 parents 948b3f5 + 85996a7 commit 4742236
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 85 deletions.
1 change: 1 addition & 0 deletions pack-bitmap-write.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ void bitmap_writer_select_commits(struct commit **indexed_commits,
if (indexed_commits_nr < 100) {
for (i = 0; i < indexed_commits_nr; ++i)
push_bitmapped_commit(indexed_commits[i]);
stop_progress(&writer.progress);
return;
}

Expand Down
116 changes: 66 additions & 50 deletions progress.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,57 +46,14 @@ struct progress {
};

static volatile sig_atomic_t progress_update;
static struct progress *global_progress;

/*
* These are only intended for testing the progress output, i.e. exclusively
* for 'test-tool progress'.
*/
int progress_testing;
uint64_t progress_test_ns = 0;
void progress_test_force_update(void)
{
progress_update = 1;
}


static void progress_interval(int signum)
{
progress_update = 1;
}

static void set_progress_signal(void)
{
struct sigaction sa;
struct itimerval v;

if (progress_testing)
return;

progress_update = 0;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = progress_interval;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa, NULL);

v.it_interval.tv_sec = 1;
v.it_interval.tv_usec = 0;
v.it_value = v.it_interval;
setitimer(ITIMER_REAL, &v, NULL);
}

static void clear_progress_signal(void)
{
struct itimerval v = {{0,},};

if (progress_testing)
return;

setitimer(ITIMER_REAL, &v, NULL);
signal(SIGALRM, SIG_IGN);
progress_update = 0;
}

static int is_foreground_fd(int fd)
{
Expand Down Expand Up @@ -135,7 +92,8 @@ static void display(struct progress *progress, uint64_t n, const char *done)
}

if (show_update) {
if (is_foreground_fd(fileno(stderr)) || done) {
int stderr_is_foreground_fd = is_foreground_fd(fileno(stderr));
if (stderr_is_foreground_fd || done) {
const char *eol = done ? done : "\r";
size_t clear_len = counters_sb->len < last_count_len ?
last_count_len - counters_sb->len + 1 :
Expand All @@ -159,7 +117,8 @@ static void display(struct progress *progress, uint64_t n, const char *done)
fprintf(stderr, "%s: %s%*s", progress->title,
counters_sb->buf, (int) clear_len, eol);
}
fflush(stderr);
if (stderr_is_foreground_fd)
fflush(stderr);
}
progress_update = 0;
}
Expand Down Expand Up @@ -249,6 +208,62 @@ void display_progress(struct progress *progress, uint64_t n)
display(progress, n, NULL);
}

static void progress_interval(int signum)
{
progress_update = 1;
}

/*
* The progress_test_force_update() function is intended for testing
* the progress output, i.e. exclusively for 'test-tool progress'.
*/
void progress_test_force_update(void)
{
progress_interval(SIGALRM);
}

static void set_progress_signal(struct progress *progress)
{
struct sigaction sa;
struct itimerval v;

if (global_progress)
BUG("should have no global_progress in set_progress_signal()");
global_progress = progress;

if (progress_testing)
return;

progress_update = 0;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = progress_interval;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa, NULL);

v.it_interval.tv_sec = 1;
v.it_interval.tv_usec = 0;
v.it_value = v.it_interval;
setitimer(ITIMER_REAL, &v, NULL);
}

static void clear_progress_signal(struct progress *progress)
{
struct itimerval v = {{0,},};

if (!global_progress)
BUG("should have a global_progress in clear_progress_signal()");
global_progress = NULL;

if (progress_testing)
return;

setitimer(ITIMER_REAL, &v, NULL);
signal(SIGALRM, SIG_IGN);
progress_update = 0;
}

static struct progress *start_progress_delay(const char *title, uint64_t total,
unsigned delay, unsigned sparse)
{
Expand All @@ -264,7 +279,7 @@ static struct progress *start_progress_delay(const char *title, uint64_t total,
strbuf_init(&progress->counters_sb, 0);
progress->title_len = utf8_strwidth(title);
progress->split = 0;
set_progress_signal();
set_progress_signal(progress);
trace2_region_enter("progress", title, the_repository);
return progress;
}
Expand Down Expand Up @@ -325,15 +340,16 @@ void stop_progress(struct progress **p_progress)
finish_if_sparse(*p_progress);

if (*p_progress) {
struct progress *progress = *p_progress;
trace2_data_intmax("progress", the_repository, "total_objects",
(*p_progress)->total);

if ((*p_progress)->throughput)
trace2_data_intmax("progress", the_repository,
"total_bytes",
(*p_progress)->throughput->curr_total);
progress->throughput->curr_total);

trace2_region_leave("progress", (*p_progress)->title, the_repository);
trace2_region_leave("progress", progress->title, the_repository);
}

stop_progress_msg(p_progress, _("done"));
Expand Down Expand Up @@ -367,7 +383,7 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
display(progress, progress->last_value, buf);
free(buf);
}
clear_progress_signal();
clear_progress_signal(progress);
strbuf_release(&progress->counters_sb);
if (progress->throughput)
strbuf_release(&progress->throughput->display);
Expand Down
43 changes: 30 additions & 13 deletions t/helper/test-progress.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
*
* Reads instructions from standard input, one instruction per line:
*
* "start[ <total>[ <title>]]" - Call start_progress(title, total),
* when "start" use a title of
* "Working hard" with a total of 0.
* "progress <items>" - Call display_progress() with the given item count
* as parameter.
* "throughput <bytes> <millis> - Call display_throughput() with the given
* byte count as parameter. The 'millis'
* specify the time elapsed since the
* start_progress() call.
* "update" - Set the 'progress_update' flag.
* "stop" - Call stop_progress().
*
* See 't0500-progress-display.sh' for examples.
*/
Expand All @@ -22,31 +26,41 @@

int cmd__progress(int argc, const char **argv)
{
int total = 0;
const char *title;
const char *default_title = "Working hard";
char *detached_title = NULL;
struct strbuf line = STRBUF_INIT;
struct progress *progress;
struct progress *progress = NULL;

const char *usage[] = {
"test-tool progress [--total=<n>] <progress-title>",
"test-tool progress <stdin",
NULL
};
struct option options[] = {
OPT_INTEGER(0, "total", &total, "total number of items"),
OPT_END(),
};

argc = parse_options(argc, argv, NULL, options, usage, 0);
if (argc != 1)
die("need a title for the progress output");
title = argv[0];
if (argc)
usage_with_options(usage, options);

progress_testing = 1;
progress = start_progress(title, total);
while (strbuf_getline(&line, stdin) != EOF) {
char *end;

if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
if (!strcmp(line.buf, "start")) {
progress = start_progress(default_title, 0);
} else if (skip_prefix(line.buf, "start ", (const char **) &end)) {
uint64_t total = strtoull(end, &end, 10);
if (*end == '\0') {
progress = start_progress(default_title, total);
} else if (*end == ' ') {
free(detached_title);
detached_title = strbuf_detach(&line, NULL);
progress = start_progress(end + 1, total);
} else {
die("invalid input: '%s'\n", line.buf);
}
} else if (skip_prefix(line.buf, "progress ", (const char **) &end)) {
uint64_t item_count = strtoull(end, &end, 10);
if (*end != '\0')
die("invalid input: '%s'\n", line.buf);
Expand All @@ -63,12 +77,15 @@ int cmd__progress(int argc, const char **argv)
die("invalid input: '%s'\n", line.buf);
progress_test_ns = test_ms * 1000 * 1000;
display_throughput(progress, byte_count);
} else if (!strcmp(line.buf, "update"))
} else if (!strcmp(line.buf, "update")) {
progress_test_force_update();
else
} else if (!strcmp(line.buf, "stop")) {
stop_progress(&progress);
} else {
die("invalid input: '%s'\n", line.buf);
}
}
stop_progress(&progress);
free(detached_title);

return 0;
}

0 comments on commit 4742236

Please sign in to comment.