Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Jan 2008 07:40:04 GMT
From:      Giorgos Keramidas <keramida@FreeBSD.org>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/119705: [PATCH] make iostat a bit smarter about the number of tty rows
Message-ID:  <200801160740.m0G7e4JL087071@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/119705; it has been noted by GNATS.

From: Giorgos Keramidas <keramida@freebsd.org>
To: Maxim Konovalov <maxim@macomnet.ru>
Cc: Bruce Evans <bde@freebsd.org>, bug-followup@freebsd.org
Subject: Re: bin/119705: [PATCH] make iostat a bit smarter about the number
	of tty rows
Date: Wed, 16 Jan 2008 09:39:37 +0200

 On 2008-01-16 09:13, Giorgos Keramidas <keramida@freebsd.org> wrote:
 > On 2008-01-16 09:29, Maxim Konovalov <maxim@macomnet.ru> wrote:
 > > Hi Giorgos,
 > > It seems for me you forget to clear wresized flag -- I added
 > > printf("%s\n", __func__); at the beginning of doresize() to notice
 > > this.
 >
 > Indeed.  Thanks for catching this.
 >
 > > IMHO the isatty() check doesn't belong to a pseudo signal handler
 > > doresize().  Install SIGWINCH handler if and only if stdout is a tty.
 >
 > That's a good suggestion too, and it will save one isatty() call for
 > each SIGWINCH delivery.  I'll update the patch and follow-up with a
 > second version in the PR.  Nice...
 
 Both fixed, I think.  The new version of the patch is attached below,
 after the following changes:
 
   iostat-rows: fix a couple of nits reported by maxim
 
   * Reset wresized when doresize() completes its work
   * Only call isatty(fileno(stdout)) once, instead of every time
   doresize() is called
   * Only install a SIGWINCH handler if isatty() is true
 
   While here, also fix another potential problem, when a terminal
   has 3 rows or less. Instead of blindly subtracting 3 from w.ws_row
   and ending up with a negative wrows value, default to 20 in that
   case.
 
   Since the traditional value of 20 rows is now used in two places with
   this change, #define it as IOSTAT_DEFAULT_ROWS, to avoid repeating a
   magic number multiple times.
 
 %%%
 diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c
 --- a/usr.sbin/iostat/iostat.c
 +++ b/usr.sbin/iostat/iostat.c
 @@ -113,6 +113,7 @@
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
 +#include <termios.h>
  #include <unistd.h>
  #include <limits.h>
  #include <devstat.h>
 @@ -131,17 +132,23 @@ struct nlist namelist[] = {
  	{ NULL },
  };
 
 +#define	IOSTAT_DEFAULT_ROWS	20	/* Traditional default `wrows' */
 +
  struct statinfo cur, last;
  int num_devices;
  struct device_selection *dev_select;
  int maxshowdevs;
  volatile sig_atomic_t headercount;
 +volatile sig_atomic_t wresized;		/* Tty resized, when non-zero. */
 +unsigned short wrows;			/* Current number of tty rows. */
  int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
  int xflag = 0, zflag = 0;
 
  /* local function declarations */
  static void usage(void);
  static void needhdr(int signo);
 +static void needresize(int signo);
 +static void doresize(void);
  static void phdr(void);
  static void devstats(int perf_select, long double etime, int havelast);
  static void cpustats(void);
 @@ -426,6 +433,20 @@ main(int argc, char **argv)
  	 */
  	(void)signal(SIGCONT, needhdr);
 
 +	/*
 +	 * If our standard output is a tty, then install a SIGWINCH handler
 +	 * and set wresized so that our first iteration through the main
 +	 * iostat loop will peek at the terminal's current rows to find out
 +	 * how many lines can fit in a screenful of output.
 +	 */
 +	if (isatty(fileno(stdout)) != 0) {
 +		wresized = 1;
 +		(void)signal(SIGWINCH, needresize);
 +	} else {
 +		wrows = IOSTAT_DEFAULT_ROWS;
 +		return;
 +	}
 +
  	for (headercount = 1;;) {
  		struct devinfo *tmp_dinfo;
  		long tmp;
 @@ -451,7 +472,9 @@ main(int argc, char **argv)
 
  		if (!--headercount) {
  			phdr();
 -			headercount = 20;
 +			if (wresized != 0)
 +				doresize();
 +			headercount = wrows;
  		}
 
  		tmp_dinfo = last.dinfo;
 @@ -493,7 +516,9 @@ main(int argc, char **argv)
  				break;
  			case 1:
  				phdr();
 -				headercount = 20;
 +				if (wresized != 0)
 +					doresize();
 +				headercount = wrows;
  				break;
  			default:
  				break;
 @@ -528,7 +553,9 @@ main(int argc, char **argv)
  				break;
  			case 1:
  				phdr();
 -				headercount = 20;
 +				if (wresized != 0)
 +					doresize();
 +				headercount = wrows;
  				break;
  			default:
  				break;
 @@ -587,6 +614,48 @@ needhdr(int signo)
  {
 
  	headercount = 1;
 +}
 +
 +/*
 + * When the terminal is resized, force an update of the maximum number of rows
 + * printed between each header repetition.  Then force a new header to be
 + * prepended to the next output.
 + */
 +void
 +needresize(int signo)
 +{
 +
 +	wresized = 1;
 +	headercount = 1;
 +}
 +
 +/*
 + * Update the global `wrows' count of terminal rows.
 + */
 +void
 +doresize(void)
 +{
 +	int status;
 +	struct winsize w;
 +
 +	printf("wresized = %d\n", wresized);
 +	for (;;) {
 +		status = ioctl(fileno(stdout), TIOCGWINSZ, &w);
 +		if (status == -1 && errno == EINTR)
 +			continue;
 +		else if (status == -1)
 +			err(1, "ioctl");
 +		if (w.ws_row > 3)
 +			wrows = w.ws_row - 3;
 +		else
 +			wrows = IOSTAT_DEFAULT_ROWS;
 +		break;
 +	}
 +
 +	/*
 +	 * Inhibit doresize() calls until we are rescheduled by SIGWINCH.
 +	 */
 +	wresized = 0;
  }
 
  static void
 %%%



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801160740.m0G7e4JL087071>