From nobody@FreeBSD.org  Tue Mar  8 12:36:47 2011
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 5B3DF1065678
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  8 Mar 2011 12:36:47 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 3FB048FC1C
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  8 Mar 2011 12:36:47 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p28Cal7U092510
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 8 Mar 2011 12:36:47 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id p28Cakfi092509;
	Tue, 8 Mar 2011 12:36:46 GMT
	(envelope-from nobody)
Message-Id: <201103081236.p28Cakfi092509@red.freebsd.org>
Date: Tue, 8 Mar 2011 12:36:46 GMT
From: Andy Farkas <chuzzwassa@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: [patch] grdc(6) timing loop still broken
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         155374
>Category:       bin
>Synopsis:       [patch] grdc(6) timing loop still broken
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 08 12:40:09 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Andy Farkas
>Release:        8.2-STABLE
>Organization:
>Environment:
FreeBSD 8.2-STABLE #0: Mon Mar  7 07:46:31 EST 2011 
>Description:
After adding a small delay loop to the scrolling code of grdc(6) I noticed
that it was not keeping time properly.

This patch adds a delay during scrolling so that you can actually see it,
and also corrects the timing calculations within the do() loop.

The scrolling bit is trivial, see my followup to bin/151663.

The main thrust of this patch is to finally fix the timing of the do() loop:

1/ at the start of the loop we get the current time (now).
2/ we diplay the time, which may take some time, especially if scrolling.
3/ after display we get the time again (delay).
4/ we then calculate the amount of time needed to wait until a whole second has passed (wait).

>How-To-Repeat:
Add a delay during scrolling and notice how the time is displayed wrong.

>Fix:
patch (including scrolling patch):

%%%
--- /usr/src/games/grdc/grdc.c	2010-08-28 13:04:04.000000000 +1000
+++ ./grdc.c	2011-03-08 22:04:00.000000000 +1000
@@ -26,7 +26,12 @@
 #define XLENGTH 58
 #define YDEPTH  7
 
-struct timespec now;
+/* now:		current time we start the loop
+   delay:	current time we finish displaying the time
+   wait:	amount of time we wait until next now second
+   scrold:	amount of time between scrolling
+*/
+struct timespec delay, now, wait, scrold;
 struct tm *tm;
 
 short disp[11] = {
@@ -54,8 +59,6 @@
 int
 main(int argc, char *argv[])
 {
-	struct timespec delay;
-	time_t prev_sec;
 	long t, a;
 	int i, j, s, k;
 	int n;
@@ -69,6 +72,7 @@
 	switch (ch) {
 	case 's':
 		scrol = 1;
+		scrold.tv_nsec = 40000000;
 		break;
 	case 't':
 		t12 = 1;
@@ -138,9 +142,9 @@
 
 		attrset(COLOR_PAIR(2));
 	}
-	clock_gettime(CLOCK_REALTIME_FAST, &now);
-	prev_sec = now.tv_sec;
+
 	do {
+		clock_gettime(CLOCK_REALTIME_FAST, &now);
 		mask = 0;
 		tm = localtime(&now.tv_sec);
 		set(tm->tm_sec%10, 0);
@@ -191,25 +195,31 @@
 				}
 				if(!s) {
 					refresh();
+					nanosleep(&scrold, NULL);
 				}
 			}
 		}
 		movto(6, 0);
 		refresh();
-		clock_gettime(CLOCK_REALTIME_FAST, &now);
-		if (now.tv_sec == prev_sec) {
-			if (delay.tv_nsec > 0) {
-				delay.tv_sec = 0;
-				delay.tv_nsec = 1000000000 - now.tv_nsec;
-			} else {
-				delay.tv_sec = 1;
-				delay.tv_nsec = 0;
+
+		clock_gettime(CLOCK_REALTIME_FAST, &delay);
+
+		if (delay.tv_sec == now.tv_sec) {
+			wait.tv_nsec = 1000000000 - (delay.tv_nsec - now.tv_nsec);
+			--n;
+		}
+		else {
+			if (delay.tv_nsec < now.tv_nsec) {
+				wait.tv_nsec = now.tv_nsec - delay.tv_nsec;
+				n -= delay.tv_sec - now.tv_sec;
+			}
+			else {
+				wait.tv_nsec = (1000000000 - delay.tv_nsec) + now.tv_nsec;
+				n -= (delay.tv_sec - now.tv_sec) + 1;
 			}
-			nanosleep(&delay, NULL);
-			clock_gettime(CLOCK_REALTIME_FAST, &now);
 		}
-		n -= now.tv_sec - prev_sec;
-		prev_sec = now.tv_sec;
+		nanosleep(&wait, NULL);
+
 		if (sigtermed) {
 			standend();
 			clear();


>Release-Note:
>Audit-Trail:
>Unformatted:
