]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
progress-bar: Add unbuffered variant 34198/head
authorAdrian Vovk <adrianvovk@gmail.com>
Sat, 31 Aug 2024 02:39:17 +0000 (22:39 -0400)
committerAdrian Vovk <adrianvovk@gmail.com>
Sat, 31 Aug 2024 02:50:24 +0000 (22:50 -0400)
The progress_bar functions do their own buffering: they reconfigure
stderr, then print, then flush and disable buffering on their own. In
situations where multiple progress bars are being drawn at a time (for
example, in updatectl), it's even more efficient to hoist the buffering
and flushing to the call site, and avoid drawing each progress bar
individually.

To that end, new _unbuffered variants of the progress_bar functions. And
we use them in updatectl.

src/shared/pretty-print.c
src/shared/pretty-print.h
src/sysupdate/updatectl.c

index b2a1393fceafe38841ac1e6d13b5d6d99cd3c52e..cc226e72ea7ce3c23c388e2579b6428fab42a385 100644 (file)
@@ -460,14 +460,7 @@ bool shall_tint_background(void) {
         return cache != 0;
 }
 
-void draw_progress_bar(const char *prefix, double percentage) {
-
-        /* We are going output a bunch of small strings that shall appear as a single line to STDERR which is
-         * unbuffered by default. Let's temporarily turn on full buffering, so that this is passed to the tty
-         * as a single buffer, to make things more efficient. */
-        char buffer[LONG_LINE_MAX];
-        setvbuf(stderr, buffer, _IOFBF, sizeof(buffer));
-
+void draw_progress_bar_unbuffered(const char *prefix, double percentage) {
         fputc('\r', stderr);
         if (prefix) {
                 fputs(prefix, stderr);
@@ -520,17 +513,10 @@ void draw_progress_bar(const char *prefix, double percentage) {
                 fputs(ANSI_ERASE_TO_END_OF_LINE, stderr);
 
         fputc('\r', stderr);
-        fflush(stderr);
 
-        /* Disable buffering again */
-        setvbuf(stderr, NULL, _IONBF, 0);
 }
 
-void clear_progress_bar(const char *prefix) {
-
-        char buffer[LONG_LINE_MAX];
-        setvbuf(stderr, buffer, _IOFBF, sizeof(buffer));
-
+void clear_progress_bar_unbuffered(const char *prefix) {
         fputc('\r', stderr);
 
         if (terminal_is_dumb())
@@ -542,8 +528,31 @@ void clear_progress_bar(const char *prefix) {
                 fputs(ANSI_ERASE_TO_END_OF_LINE, stderr);
 
         fputc('\r', stderr);
+}
+
+void draw_progress_bar(const char *prefix, double percentage) {
+
+        /* We are going output a bunch of small strings that shall appear as a single line to STDERR which is
+         * unbuffered by default. Let's temporarily turn on full buffering, so that this is passed to the tty
+         * as a single buffer, to make things more efficient. */
+        char buffer[LONG_LINE_MAX];
+        setvbuf(stderr, buffer, _IOFBF, sizeof(buffer));
+
+        draw_progress_bar_unbuffered(prefix, percentage);
+
         fflush(stderr);
 
         /* Disable buffering again */
         setvbuf(stderr, NULL, _IONBF, 0);
 }
+
+void clear_progress_bar(const char *prefix) {
+        char buffer[LONG_LINE_MAX];
+        setvbuf(stderr, buffer, _IOFBF, sizeof(buffer));
+
+        clear_progress_bar_unbuffered(prefix);
+
+        fflush(stderr);
+
+        setvbuf(stderr, NULL, _IONBF, 0);
+}
index 2c97c354ef08c73eaba7f58e8bfd20552d42592d..d3af149a2ef8e94a79fb882ee686968e0fd18082 100644 (file)
@@ -55,3 +55,5 @@ bool shall_tint_background(void);
 
 void draw_progress_bar(const char *prefix, double percentage);
 void clear_progress_bar(const char *prefix);
+void draw_progress_bar_unbuffered(const char *prefix, double percentage);
+void clear_progress_bar_unbuffered(const char *prefix);
index 400e521c1ba7148967b89caea34a44980e98f882..c298b244641951bba51dcdbdef433e7207884f7a 100644 (file)
@@ -13,6 +13,7 @@
 #include "bus-map-properties.h"
 #include "bus-util.h"
 #include "errno-list.h"
+#include "fileio.h"
 #include "format-table.h"
 #include "json-util.h"
 #include "main-func.h"
@@ -795,6 +796,11 @@ static int update_render_progress(sd_event_source *source, void *userdata) {
         if (n == 0)
                 return 0;
 
+        /* We're outputting lots of small strings to STDERR, which is unbuffered by default. So let's turn
+         * on full buffering, so we pass this all to the TTY in one go, to make things more efficient */
+        char buffer[LONG_LINE_MAX];
+        setvbuf(stderr, buffer, _IOFBF, sizeof(buffer));
+
         if (!terminal_is_dumb()) {
                 for (size_t i = 0; i <= n; i++)
                         fputs("\n", stderr); /* Possibly scroll the terminal to make room (including total)*/
@@ -809,23 +815,23 @@ static int update_render_progress(sd_event_source *source, void *userdata) {
                 int progress = PTR_TO_INT(p);
 
                 if (progress == UPDATE_PROGRESS_FAILED) {
-                        clear_progress_bar(target);
+                        clear_progress_bar_unbuffered(target);
                         fprintf(stderr, "%s: %s Unknown failure\n", target, RED_CROSS_MARK());
                         total += 100;
                 } else if (progress == -EALREADY) {
-                        clear_progress_bar(target);
+                        clear_progress_bar_unbuffered(target);
                         fprintf(stderr, "%s: %s Already up-to-date\n", target, GREEN_CHECK_MARK());
                         n--; /* Don't consider this target in the total */
                 } else if (progress < 0) {
-                        clear_progress_bar(target);
+                        clear_progress_bar_unbuffered(target);
                         fprintf(stderr, "%s: %s %s\n", target, RED_CROSS_MARK(), STRERROR(progress));
                         total += 100;
                 } else if (progress == UPDATE_PROGRESS_DONE) {
-                        clear_progress_bar(target);
+                        clear_progress_bar_unbuffered(target);
                         fprintf(stderr, "%s: %s Done\n", target, GREEN_CHECK_MARK());
                         total += 100;
                 } else {
-                        draw_progress_bar(target, progress);
+                        draw_progress_bar_unbuffered(target, progress);
                         fputs("\n", stderr);
                         total += progress;
                 }
@@ -833,9 +839,9 @@ static int update_render_progress(sd_event_source *source, void *userdata) {
 
         if (n > 1) {
                 if (exiting)
-                        clear_progress_bar(target);
+                        clear_progress_bar_unbuffered(target);
                 else {
-                        draw_progress_bar("Total", (double) total / n);
+                        draw_progress_bar_unbuffered("Total", (double) total / n);
                         if (terminal_is_dumb())
                                 fputs("\n", stderr);
                 }
@@ -850,6 +856,7 @@ static int update_render_progress(sd_event_source *source, void *userdata) {
                 fputs("------\n", stderr);
 
         fflush(stderr);
+        setvbuf(stderr, NULL, _IONBF, 0); /* Disable buffering again */
         return 0;
 }