Subject: [PATCH 2/2] progress: add a shutting down state to the SIGALRM handler

From: "Carlo Marcelo Arenas Belón via GitGitGadget" <[email-masked]>
Date: Sat, 23 Aug 2025 13:22:57 +0000

From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= <[email-masked]>

In a previous commit, sigitimer() was replaced by alarm(), but to
keep the timer active, an extra call to `alarm(1)` was added to
the signal handler, opening a potential race condition whem the
timer is being cleared.

To avoid that, add an extra state to set during shutdown and
adjust the logic to flag the potential need to update progress
into the first bit instead.

Signed-off-by: Carlo Marcelo Arenas Belón <[email-masked]>
---
 progress.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/progress.c b/progress.c
index 71b305d1625d..49e58e094a3f 100644
--- a/progress.c
+++ b/progress.c
@@ -50,6 +50,11 @@ struct progress {
 	int split;
 };
 
+/*
+ * 0: no progress to report
+ * 1: potential update for progress to report
+ * 2: no more progress to report
+ */
 static volatile sig_atomic_t progress_update;
 
 /*
@@ -66,8 +71,10 @@ void progress_test_force_update(void)
 
 static void progress_interval(int signum UNUSED)
 {
-	progress_update = 1;
-	alarm(1);
+	if (progress_update != 2) {
+		alarm(1);
+		progress_update = 1;
+	}
 }
 
 static void set_progress_signal(void)
@@ -93,6 +100,7 @@ static void clear_progress_signal(void)
 	if (progress_testing)
 		return;
 
+	progress_update = 2;
 	alarm(0);
 	signal(SIGALRM, SIG_IGN);
 	progress_update = 0;
@@ -111,14 +119,14 @@ static void display(struct progress *progress, uint64_t n, const char *done)
 	int show_update = 0;
 	int last_count_len = counters_sb->len;
 
-	if (progress->delay && (!progress_update || --progress->delay))
+	if (progress->delay && (!(progress_update & 1) || --progress->delay))
 		return;
 
 	progress->last_value = n;
 	tp = (progress->throughput) ? progress->throughput->display.buf : "";
 	if (progress->total) {
 		unsigned percent = n * 100 / progress->total;
-		if (percent != progress->last_percent || progress_update) {
+		if (percent != progress->last_percent || (progress_update & 1)) {
 			progress->last_percent = percent;
 
 			strbuf_reset(counters_sb);
@@ -128,7 +136,7 @@ static void display(struct progress *progress, uint64_t n, const char *done)
 				    tp);
 			show_update = 1;
 		}
-	} else if (progress_update) {
+	} else if (progress_update & 1) {
 		strbuf_reset(counters_sb);
 		strbuf_addf(counters_sb, "%"PRIuMAX"%s", (uintmax_t)n, tp);
 		show_update = 1;
@@ -239,7 +247,7 @@ void display_throughput(struct progress *progress, uint64_t total)
 	tp->idx = (tp->idx + 1) % TP_IDX_MAX;
 
 	throughput_string(&tp->display, total, rate);
-	if (progress->last_value != -1 && progress_update)
+	if (progress->last_value != -1 && (progress_update & 1))
 		display(progress, progress->last_value, NULL);
 }
 
-- 
gitgitgadget