[pacman-dev] [PATCH 2/2] cache terminal size, add SIGWINCH handler to reset

Dave Reisner dreisner at archlinux.org
Tue Jun 24 16:32:32 EDT 2014


Refactoring getcols, yet again. We do the following:

1) Introduce a static global in src/pacman/util.c
2) getcols always prefers this cached value, but will derive it from
the COLUMNS environment var, the characteristics of stdout, or a sane
default (in that order).
3) Introduce a SIGWINCH signal handler to reset the cached value,
meaning we only call ioctl when we don't know the value.

On my machine, pacman -Syy goes from ~4300 ioctl calls to 3.
---
 src/pacman/callback.c |  6 +++---
 src/pacman/package.c  |  4 ++--
 src/pacman/pacman.c   |  5 ++++-
 src/pacman/util.c     | 59 +++++++++++++++++++++++++++++++++++++--------------
 src/pacman/util.h     |  3 ++-
 5 files changed, 54 insertions(+), 23 deletions(-)

diff --git a/src/pacman/callback.c b/src/pacman/callback.c
index 9cde1de..6be20ec 100644
--- a/src/pacman/callback.c
+++ b/src/pacman/callback.c
@@ -424,7 +424,7 @@ void cb_question(alpm_question_t *question)
 							"The following package cannot be upgraded due to unresolvable dependencies:\n",
 							"The following packages cannot be upgraded due to unresolvable dependencies:\n",
 							count));
-				list_display("     ", namelist, getcols(fileno(stdout)));
+				list_display("     ", namelist, getcols());
 				printf("\n");
 				q->skip = noyes(_n(
 							"Do you want to skip the above package for this upgrade?",
@@ -494,7 +494,7 @@ void cb_progress(alpm_progress_t event, const char *pkgname, int percent,
 	int len, wclen, wcwid, padwid;
 	wchar_t *wcstr;
 
-	const unsigned short cols = getcols(fileno(stdout));
+	const unsigned short cols = getcols();
 
 	if(config->noprogressbar || cols == 0) {
 		return;
@@ -664,7 +664,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)
 	const char *rate_label, *xfered_label;
 	int file_percent = 0, total_percent = 0;
 
-	const unsigned short cols = getcols(fileno(stdout));
+	const unsigned short cols = getcols();
 
 	if(config->noprogressbar || cols == 0 || file_total == -1) {
 		if(file_xfered == 0) {
diff --git a/src/pacman/package.c b/src/pacman/package.c
index 3be996d..1ac0fca 100644
--- a/src/pacman/package.c
+++ b/src/pacman/package.c
@@ -140,7 +140,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra)
 		optionalfor = alpm_pkg_compute_optionalfor(pkg);
 	}
 
-	cols = getcols(fileno(stdout));
+	cols = getcols();
 
 	/* actual output */
 	if(from == ALPM_PKG_FROM_SYNCDB) {
@@ -404,7 +404,7 @@ int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status)
 		return 1;
 	}
 
-	cols = getcols(fileno(stdout));
+	cols = getcols();
 	for(i = searchlist; i; i = alpm_list_next(i)) {
 		alpm_list_t *grp;
 		alpm_pkg_t *pkg = i->data;
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index e8c5f9e..ec200a9 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -312,6 +312,9 @@ static void handler(int signum)
 			/* a transaction is being interrupted, don't exit pacman yet. */
 			return;
 		}
+	} else if(signum == SIGWINCH) {
+		columns_cache_reset();
+		return;
 	}
 	/* SIGINT/SIGHUP: no committing transaction, release it now and then exit pacman
 	 * SIGTERM: release no matter what */
@@ -1019,7 +1022,7 @@ int main(int argc, char *argv[])
 	int ret = 0;
 	size_t i;
 	struct sigaction new_action, old_action;
-	const int signals[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV };
+	const int signals[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV, SIGWINCH };
 	uid_t myuid = getuid();
 
 	/* Set signal handlers */
diff --git a/src/pacman/util.c b/src/pacman/util.c
index ebf15db..9244870 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -46,6 +46,7 @@
 #include "conf.h"
 #include "callback.h"
 
+static int cached_columns = 0;
 
 struct table_cell_t {
 	char *label;
@@ -155,29 +156,55 @@ static int flush_term_input(int fd)
 	return 0;
 }
 
-/* gets the current screen column width */
-unsigned short getcols(int fd)
-{
-	const unsigned short default_tty = 80;
-	const unsigned short default_notty = 0;
-	unsigned short termwidth = 0;
+void columns_cache_reset() {
+	cached_columns = 0;
+}
 
-	if(!isatty(fd)) {
-		return default_notty;
-	}
+static int getcols_fd(int fd) {
+	int width = -1;
 
 #if defined(TIOCGSIZE)
 	struct ttysize win;
 	if(ioctl(fd, TIOCGSIZE, &win) == 0) {
-		termwidth = win.ts_cols;
+		width = win.ts_cols;
 	}
 #elif defined(TIOCGWINSZ)
 	struct winsize win;
 	if(ioctl(fd, TIOCGWINSZ, &win) == 0) {
-		termwidth = win.ws_col;
+		width = win.ws_col;
 	}
 #endif
-	return termwidth == 0 ? default_tty : termwidth;
+
+	if(width <= 0) {
+		return -EIO;
+	}
+
+	return width;
+}
+
+unsigned short getcols(void) {
+	const char *e;
+	int c = 0;
+
+	if(cached_columns > 0) {
+		return cached_columns;
+	}
+
+	e = getenv("COLUMNS");
+	if(e) {
+		c = strtol(e, NULL, 10);
+	}
+
+	if(c <= 0) {
+		c = getcols_fd(STDOUT_FILENO);
+	}
+
+	if(c <= 0) {
+		c = 80;
+	}
+
+	cached_columns = c;
+	return c;
 }
 
 /* does the same thing as 'rm -rf' */
@@ -892,7 +919,7 @@ static void _display_targets(alpm_list_t *targets, int verbose)
 	pm_asprintf(&str, "%s (%zd)", _("Packages"), alpm_list_count(targets));
 	printf("\n");
 
-	cols = getcols(fileno(stdout));
+	cols = getcols();
 	if(verbose) {
 		header = create_verbose_header(alpm_list_count(targets));
 		if(table_display(header, rows, cols) != 0) {
@@ -1196,7 +1223,7 @@ void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg)
 
 	if(optstrings) {
 		printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg));
-		unsigned short cols = getcols(fileno(stdout));
+		unsigned short cols = getcols();
 		list_display_linebreak("   ", optstrings, cols);
 	}
 
@@ -1218,7 +1245,7 @@ void display_optdepends(alpm_pkg_t *pkg)
 
 	if(optstrings) {
 		printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg));
-		unsigned short cols = getcols(fileno(stdout));
+		unsigned short cols = getcols();
 		list_display_linebreak("   ", optstrings, cols);
 	}
 
@@ -1241,7 +1268,7 @@ void select_display(const alpm_list_t *pkglist)
 	alpm_list_t *list = NULL;
 	char *string = NULL;
 	const char *dbname = NULL;
-	unsigned short cols = getcols(fileno(stdout));
+	unsigned short cols = getcols();
 
 	for(i = pkglist; i; i = i->next) {
 		alpm_pkg_t *pkg = i->data;
diff --git a/src/pacman/util.h b/src/pacman/util.h
index 4a31e89..b591fba 100644
--- a/src/pacman/util.h
+++ b/src/pacman/util.h
@@ -49,7 +49,8 @@ int trans_init(alpm_transflag_t flags, int check_valid);
 int trans_release(void);
 int needs_root(void);
 int check_syncdbs(size_t need_repos, int check_valid);
-unsigned short getcols(int fd);
+unsigned short getcols(void);
+void columns_cache_reset(void);
 int rmrf(const char *path);
 void indentprint(const char *str, unsigned short indent, unsigned short cols);
 size_t strtrim(char *str);
-- 
2.0.0



More information about the pacman-dev mailing list