Daniel Silverstone Moving your comfort zone

Over time, I've discussed with many people how they learn a new programming language. A common theme is to write something you're intimately familiar with over again in a new language in order to learn and judge. For example, some of my friends like to implement standard *NIX utilities such as cat, echo, grep etc. Usually only trivial versions, but it gives them a feel for stdio, file access, command line argument processing, etc. Some implement some kind of algorithmic solution to a known problem in order to get a good feel for control structures and approaches to data structures. I am a little bit in both camps. I tend to try and use controlled problems but I try not to reimplement things over and over. Over-all any of these approaches are excellent in allowing the developer to gain an understanding of how a language works, and how to solve things in it. Learning your tools is key to being an effective developer, and the language you're working in is one of those tools.

Sometimes though, what you want to do is extend your knowledge in a different direction. I am currently embarking on one such journey, and I'd like to tell you a little bit about it.

I have, for many years, been interested in microcontrollers, and writing software which works in severely resource-limited environments (such as a total of 20 kilobytes of RAM, or 128 kilobytes of program storage). I've been working with one such family of computing devices for quite a while now, and among my various projects I have developed USB devices which do fun things such as monitor a bidirectional serial link, providing millisecond timestamped transaction information down the USB port. However throughout it all, USB itself has remained a fairly sealed black box. I used libraries provided by the microcontroller vendor, and just programmed around them.

While I was away at a conference I decided though that this had to change.

I decided there and then, that I would improve my understanding of several topics all at once. I was going to learn more about the microcontroller hardware, the specifics of USB itself, and improve my command of a programming language all at once. This is, as you might imagine, quite a tall order, but I feel that it's worth my while to push my comfort zone a little and do this. To keep me honest, and to keep me working at this, I have also committed to presenting, at a conference, some kind of results of my efforts.

I tell this story here, in part to increase the assurance that there's plenty of people expecting me to do the work, and also in part to encourage you all to push your comfort zones a little. Your homework, because of course there is some, is to think of something you do a lot, that you are comfortable, interested, and engaged with. Now think of a way to twist that so that you learn a lot more about that topic while pushing your comfort zone just a little bit. Why not comment below and tell me what you're going to do, and we can encourage one another just a little.

Posted Wed Sep 6 12:00:06 2017
Richard Maw Time - Rendering

Time-stamps are great for computers. They are just any other number that they can perform arithmetic on.

Unfortunately humans don't think of time as one big number. Humans think of time as a bunch of small numbers.

There's numbers for the position of their planet around their Star. There's the number of what year it is. The number of which month, which may even have a different name! The day of the month which there isn't even the name number of each month! Humans even count days in a cycle of 7 which have their own names!

For measuring the rotation of their planet humans have more consistent numbers. Each day is divided into 24 hours. Each hour is divided into 60 minutes. Each minute is divided into 60 seconds.

This is all a bit silly because the period of the Earth's rotation isn't even an integral number of seconds, and it's slowing down!

Forunately some considerate humans wrote functions for turning our nice friendly time-stamps from clock_gettime(2) into icky human divisions.

int ret;
struct timespec time;

ret = clock_gettime(CLOCK_REALTIME, &time);

struct timespec

For a lot of humans, seconds are a coarse enough measure of time. They track the time as a number of seconds and the number of nanoseconds between those seconds.

struct timespec {
    time_t tv_sec;
    time_t tv_nsec;
};

Forunately humans aren't strange enough to commonly render nanoseconds as anything other than nanosecond precision after the decimal point, so this fixed point number can be rendered with the %09ld printf(3) format string.

/* Render the current time as seconds and nanoseconds. */
printf("%ld.%09ld\n", (long)time.tv_sec, (long)time.tv_nsec);

struct tm

In GLibc there are two types of functions for turning a time_t into a form that humans can deal with.

There's gmtime_r(3) for getting the time in the UTC timezone (the name is weird because it used to do the GMT timezone but it's more useful in UTC and they are closely related).

There's localtime_r(3) for getting the time in whatever local time zone your computer is configured to think it is in.

If the time is only going to be shown to the user of the computer then localtime_r(3) may be more appropriate. If it's going to be shared then gmtime_r(3) would be more appropriate, especially if it's going to be shared internationally.

strftime(3)

You can use the contents of struct tm directly, but humans have a lot of their own rules for how to display time as text.

This is why they wrote strftime(3). It has its own little language for describing how to display the time.

Unfortunately humans, unlike us perfect machines, are fallible.

Humans have a notion of the same hour's number being used twice in a day and have to add their own way of saying which it is, so their language includes %p to become "AM" or "PM". Not all humans use this, so %p can produce no result. This is a problem, since a format string of just %p will result in a zero-length result, and strftime(3) also uses a zero result to mean that the memory for storing the result in is not large enough.

Humans may think this is fine and that nobody ever wants to just know whether it's "AM" or "PM", or that they just know that they provided enough memory so don't check.

We are perfect machines and want it to work for every input, so want our own wrapper to make it work.

/* Returns 0 on success, -1 on failure */
/* Some format strings can naturally expand to "",
 * which is a problem since the size is returned or 0 if too small.
 */
ssize_t safe_strftime(char *s, size_t *len, size_t max, const char *format,
                      const struct tm *tm) {
    /* Adds a trailing space to format string
     * so it always gets 0 on too small,
     * and NULs it on success before returning length
     */
    char *fmt = NULL;
    ssize_t ret;

    ret = asprintf(&fmt, "%s ", format);
    if (ret < 0)
        goto cleanup;

    ret = strftime(s, max, fmt, tm);
    if (ret == 0) {
        ret = -1;
        goto cleanup;
    }

    s[ret - 1] = '\0';
    if (len)
        *len = ret - 1;
    ret = 0;

cleanup:
    free(fmt);
    return ret;
}

Since we perfect machines don't like to waste memory we needed an API that we could retry with more memory. We perfect machines also like tidy functions, so we're going to write one that reallocates internally.

/* Returns length and sets *s on success, -1 and sets errno on failure */
ssize_t astrftime(char **s, const char *fmt, const struct tm *tm) {
    ssize_t ret;
    size_t tbufsiz = 80;
    char *tbuf = NULL;
    size_t tlen;

    tbuf = malloc(tbufsiz);
    if (tbuf == NULL) {
        ret = -1;
        goto cleanup;
    }

    while (safe_strftime(tbuf, &tlen, tbufsiz, fmt, tm) != 0) {
        char *newbuf;
        size_t newsiz;

        newsiz = tbufsiz * 2;
        newbuf = realloc(tbuf, newsiz);
        if (newbuf == NULL) {
            ret = 1;
            goto cleanup;
        }

        tbuf = newbuf;
        tbufsiz = newsiz;
    }

    *s = tbuf;
    tbuf = NULL;
    ret = tlen;

cleanup:
    free(tbuf);
    return ret;
}

If time needs to be rendered in another way then it's probably better to use the contents of struct tm directly.

Command

Now we have enough to write our program.

int main(void) {
    int ret;
    struct timespec time;
    struct tm tinfo;
    char *tbuf = NULL;

    ret = clock_gettime(CLOCK_REALTIME, &time);
    if (ret != 0) {
        perror("clock_gettime");
        ret = 1;
        goto cleanup;
    }

    if (gmtime_r(&time.tv_sec, &tinfo) == NULL) {
        perror("gmtime_r");
        ret = 1;
        goto cleanup;
    }

    if (astrftime(&tbuf, "%F %T", &tinfo) < 0) {
        perror("astrftime");
        ret = 1;
        goto cleanup;
    }

    /* Render the current time as the formatted time plus nanoseconds. */
    printf("%s.%09ld\n", tbuf, (long)time.tv_nsec);

cleanup:
    free(tbuf);
    return ret;
}

Full source may be downloaded here.

$ make time
cc     time.c   -o time
$ ./time
2017-08-25 19:54:32.341259517

We briefly mentioned that the number of seconds in a year isn't constant.

We're going to elaborate on that in the next article.

Posted Wed Sep 13 12:00:12 2017 Tags:
Daniel Silverstone Psst, can you keep a secret?

Human society is based, in part, on keeping things secret. Our society (as it is) would fail horribly if everything was publically known. We rely on keeping some information secret to protect our private content. For example, we often protect access services with secrets we call passwords (though if they are simple words then it's unlikely they're very secure). We also use things called cryptographic keys which are large complicated-to-work-with numbers which computers can use to secure information.

If you've been following since we started Yakking then you've probably got some passwords and some keys of your own. Your keys might be things like SSH identities or GnuPG keys. Your passwords will protect things like your computer login, your social media accounts, etc.

As computer users, we have so many of these secrets to look after that you're unlikely to be relying on your own fallible memory. As such you're likely already getting your computer to remember them for you. If you're doing this semi-well then you're protecting all the remembered credentials with some password(s) and/or key(s).

There are many ways of looking after credentials, generating passwords, measuring the quality of passwords, handling keys, policies for retaining and changing credentials, etc. Over the next few articles we'll discuss a number of these points and hopefully you'll all feel a little more secure as a result.

Posted Wed Sep 20 12:00:11 2017 Tags:

It's common knowledge that the number of days in a year is not constant.

Since the Earth doesn't orbit the Sun in exactly 365 days and it is impractical to not have a whole number of days in the year we allow our calendar seasons to become marginally desynchronised with astronomical seasons and every four years (more or less) have a year with an extra day in it.

This is called a leap year, and contains a leap day.

There's an analogous concept of a leap second to correct the discrepancy between the Earth's rotation about its axis and the number of seconds as measured by atomic clocks.

Leap seconds

On days with a positive leap second there is an extra second in the day. To minimise disruption this second officially happens at midnight.

As a result 23:59:60 is a valid time of day.

The average person is not likely to notice that, though computers will, and since computers run software written by humans they may not handle this very well.

The default handling of this in Linux when using CLOCK_REALTIME is that 23:59:59 lasts for two seconds.

This could cause issues for software that controls things like robot arms, since an instruction to rotate for 1 second would become rotate for 2 seconds.

An alternative, handled by using Google's time servers as your NTP server, is to smear the leap second across the whole day.

Since your computer typically has to deal with your clock drifting small corrections are regularly made anyway, so this is a neat solution.

This doesn't help if your computer normally has a very reliable clock, as any software written specifically to run on it will depend on this property which is not correct for a whole day every so often.

This could be a problem for specialist control software, but it's a more serious problem for authoritative NTP servers who can't use an upstream NTP server to do the time smearing for them.

To handle this there's CLOCK_TAI which will return 23:59:60.

The leap second adjustments are handled by adjtimex(2), applying a time smear if using Google's time servers, or inserting a leap second into the day.


With the discussion of CLOCK_TAI we have discussed all the clocks that measure the passage of time.

Another type of clock for measuring a different notion of time is the CPU clock, for accounting how much CPU a process or thread uses, which will be discussed at another time.

Posted Wed Sep 27 12:00:13 2017 Tags: