A surprising missing Unix command: waiting until a time is reached

August 17, 2016

I tweeted:

A surprising missing Unix command: 'sleep until it is time <X> or later'. Even GNU sleep only sleeps for a duration.

The obvious option here is at, but at has a number of drawbacks that make it far from an ideal experience. For now, I'll just note that it of course runs your commands non-interactively, and sometimes you need interactivity. Perhaps you're doing:

waituntil 17:50; rsync -a login@host:/some/thing .

(Which is in fact more or less one of the things that I wanted this for today.)

Original V7 Unix of course had a perfectly sensible reason not to bother implementing something like this, namely that you can easily put a reasonable version together by using some shell scripting to work out how many seconds to tell sleep to sleep. In the relatively minimal V7 environment, a dedicated command for waituntil would not have been quite out of place and not Unixy. Indeed, I wouldn't expect traditionally minded Unixes like the *BSDs to pick up such a program or option to sleep.

On the other hand, GNU coreutils is a different matter. The GNU people are perfectly happy to add features to traditional Unix commands (often quite handy ones), much to the despair of Unix traditionalists. They have certainly added some features to GNU sleep, like multiple arguments in multiple formats, so it wouldn't have surprised me at all if they'd added a 'sleep until absolute time <X>' option as well. But they haven't (so far) and as far as I could tell on a casual perusal of my Linux systems, no one else has written something like this and gotten it packaged so it's commonly installed.

Because sometimes I'm a system programmer as well as a sysadmin, I wound up writing my own version of a waituntil program. It's in Go because that seemed the right language and I felt like it.

(I picked Go because the hard part is parsing and manipulating the time argument, and Go actually has a quite nice and flexible system for that. This turned out somewhat more complicated than I expected, but these things happen.)

Sidebar: The right way to do this in the modern Unix API

My version of waituntil and any version that is based on top of sleep have a little problem: they don't necessarily cope with the system clock changing. If it's 16:10 now, you say 'waituntil 16:20', and a minute later the system clock jumps to 16:20, you probably want to have the wait finish right then because you've reached the target time.

As far as I can see, the correct way to do this on a modern standards-compliant Unix system is to use clock_nanosleep() with TIMER_ABSTIME to wait to an absolute time, and use CLOCK_REALTIME as the clock you're doing this against. Given this, you should be woken the moment the system's clock hits (or passes) the absolute time you specified, even if the clock is adjusted forward or backward in the mean time.

(Of course, support for this isn't necessarily there in all Unixes, at least right now.)

Unfortunately for me, Go doesn't expose clock_nanosleep() (except as a raw Linux syscall, and I don't feel like going there). For my personal use this is okay, but it would be nice to do better.

Written on 17 August 2016.
« How you tell what signals a Linux process is ignoring
Localhost is (sometimes) a network »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Wed Aug 17 23:02:47 2016
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.