[hackers] [PATCH slstatus v3] align ticks to wall-clock seconds

From: Jialu Xu <xujialu_AT_vimux.org>
Date: Sun, 31 May 2026 17:28:42 +0800

Use clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME) anchored to whole-second
boundaries derived from CLOCK_REALTIME. This eliminates drift accumulation
inherent in relative nanosleep, while avoiding the fragility of pure
CLOCK_REALTIME deadlines under suspend/resume.

Signed-off-by: Jialu Xu <xujialu_AT_vimux.org>
---
 slstatus.c | 47 +++++++++++++++++++++++++----------------------
 1 file changed, 25 insertions(+), 22 deletions(-)
v3:
- replace CLOCK_REALTIME deadlines with mixed CLOCK_REALTIME/CLOCK_MONOTONIC
  (REALTIME for alignment, MONOTONIC for absolute sleep — avoids suspend fragility)
- drop diff_ms classification (over-engineered for a status bar)
- revert datetime to time(NULL) (COARSE clock issue is one-frame only)
v2:
- classify next-now delta into advance/re-sleep/reanchor cases
- handle backward NTP steps
v1:
- initial CLOCK_REALTIME TIMER_ABSTIME approach
- switch datetime to clock_gettime(CLOCK_REALTIME)
diff --git a/slstatus.c b/slstatus.c
index 16d88fe..221b958 100644
--- a/slstatus.c
+++ b/slstatus.c
_AT_@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 #include <time.h>
 #include <X11/Xlib.h>
 
_AT_@ -30,14 +31,6 @@ terminate(const int signo)
 		done = 1;
 }
 
-static void
-difftimespec(struct timespec *res, struct timespec *a, struct timespec *b)
-{
-	res->tv_sec = a->tv_sec - b->tv_sec - (a->tv_nsec < b->tv_nsec);
-	res->tv_nsec = a->tv_nsec - b->tv_nsec +
-	               (a->tv_nsec < b->tv_nsec) * 1E9;
-}
-
 static void
 usage(void)
 {
_AT_@ -48,7 +41,8 @@ int
 main(int argc, char *argv[])
 {
 	struct sigaction act;
-	struct timespec start, current, diff, intspec, wait;
+	struct timespec wall, mono, deadline;
+	uint64_t wall_ns, offset_ns, interval_ns;
 	size_t i, len;
 	int sflag, ret;
 	char status[MAXLEN];
_AT_@ -82,10 +76,9 @@ main(int argc, char *argv[])
 	if (!sflag && !(dpy = XOpenDisplay(NULL)))
 		die("XOpenDisplay: Failed to open display");
 
-	do {
-		if (clock_gettime(CLOCK_MONOTONIC, &start) < 0)
-			die("clock_gettime:");
+	interval_ns = interval * 1000000ULL;
 
+	do {
 		status[0] = '\0';
 		for (i = len = 0; i < LEN(args); i++) {
 			if (!(res = args[i].func(args[i].args)))
_AT_@ -110,18 +103,28 @@ main(int argc, char *argv[])
 		}
 
 		if (!done) {
-			if (clock_gettime(CLOCK_MONOTONIC, &current) < 0)
+			if (clock_gettime(CLOCK_REALTIME, &wall) < 0 ||
+			    clock_gettime(CLOCK_MONOTONIC, &mono) < 0)
 				die("clock_gettime:");
-			difftimespec(&diff, &current, &start);
-
-			intspec.tv_sec = interval / 1000;
-			intspec.tv_nsec = (interval % 1000) * 1E6;
-			difftimespec(&wait, &intspec, &diff);
 
-			if (wait.tv_sec >= 0 &&
-			    nanosleep(&wait, NULL) < 0 &&
-			    errno != EINTR)
-					die("nanosleep:");
+			wall_ns = (uint64_t)wall.tv_sec * 1000000000ULL + wall.tv_nsec;
+			offset_ns = interval_ns - (wall_ns % interval_ns);
+			if (offset_ns == interval_ns)
+				offset_ns = 0;
+
+			deadline.tv_sec  = mono.tv_sec;
+			deadline.tv_nsec = mono.tv_nsec + (long)offset_ns;
+			if (deadline.tv_nsec >= 1000000000L) {
+				deadline.tv_sec++;
+				deadline.tv_nsec -= 1000000000L;
+			}
+
+			ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
+			                      &deadline, NULL);
+			if (ret != 0 && ret != EINTR) {
+				errno = ret;
+				die("clock_nanosleep:");
+			}
 		}
 	} while (!done);
 
-- 
2.47.3
Received on Sun May 31 2026 - 11:28:42 CEST

This archive was generated by hypermail 2.3.0 : Sun May 31 2026 - 11:36:36 CEST