clockid_t (clock_gettime first argument) portability

8.3k Views Asked by At

Most POSIX-compatible systems provide a function to get or set one of high-resolution timers:

int clock_gettime(clockid_t clock_id, struct timespec *tp);

Documentation for each system usually lists several symbolic names as possible clock_id values, but actual numeric values are never mentioned. It turns out that not only the numeric values are different across various systems, but symbolic names are also not the same for the same meaning. Even more so, not all the clocks actually supported by a system are defined in time.h (bits/time.h) ­— some are only defined in, let's say, linux/time.h.


That is, in a Linux system we may have:

#define CLOCK_REALTIME                  0
#define CLOCK_MONOTONIC                 1
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3
#define CLOCK_MONOTONIC_RAW             4
#define CLOCK_REALTIME_COARSE           5
#define CLOCK_MONOTONIC_COARSE          6
#define CLOCK_BOOTTIME                  7
#define CLOCK_REALTIME_ALARM            8
#define CLOCK_BOOTTIME_ALARM            9
#define CLOCK_SGI_CYCLE                10      // In linux/time.h only.
#define CLOCK_TAI                      11      // In linux/time.h only.

In Cygwin environment (not a verbatim excerpt):

#define CLOCK_REALTIME                  1       // Means CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC                 4       // Means CLOCK_MONOTONIC_RAW?
#define CLOCK_PROCESS_CPUTIME_ID        2
#define CLOCK_THREAD_CPUTIME_ID         3

In FreeBSD:

#define CLOCK_REALTIME                  0
#define CLOCK_VIRTUAL                   1
#define CLOCK_PROF                      2
#define CLOCK_MONOTONIC                 4
#define CLOCK_UPTIME                    5       // Synonymous to CLOCK_BOOTTIME?
#define CLOCK_UPTIME_PRECISE            7
#define CLOCK_UPTIME_FAST               8
#define CLOCK_REALTIME_PRECISE          9       // Same as CLOCK_REALTIME?
#define CLOCK_REALTIME_FAST            10       // Synonymous to CLOCK_REALTIME_COARSE?
#define CLOCK_MONOTONIC_PRECISE        11       // Same as CLOCK_MONOTONIC?
#define CLOCK_MONOTONIC_FAST           12       // Synonymous to CLOCK_MONOTONIC_COARSE?
#define CLOCK_SECOND                   13
#define CLOCK_THREAD_CPUTIME_ID        14
#define CLOCK_PROCESS_CPUTIME_ID       15

In AIX:

#define CLOCK_REALTIME                ...
#define CLOCK_MONOTONIC               ...
#define CLOCK_PROCESS_CPUTIME_ID      ...
#define CLOCK_THREAD_CPUTIME_ID       ...

In SunOS:

#define CLOCK_REALTIME                ...
#define CLOCK_HIGHRES                 ...       // Synonymous to CLOCK_MONOTONIC_RAW?

In QNX:

#define CLOCK_REALTIME                ...
#define CLOCK_SOFTTIME                ...
#define CLOCK_MONOTONIC               ...

And so on.


This makes me wonder how to use clock_gettime() with the first argument other than CLOCK_REALTIME in a portable way. For example, if I want to use CLOCK_MONOTONIC_COARSE or CLOCK_BOOTTIME, how do I know that BSD calls them CLOCK_MONOTONIC_FAST and CLOCK_UPTIME, respectively, instead?

Is it wise to make assumptions based on numeric values of the first 4 symbolic names? Such as:

#define POSIX_CLOCK_REALTIME            0
#define POSIX_CLOCK_MONOTONIC           1
#define POSIX_CLOCK_PROCESS_CPUTIME_ID  2
#define POSIX_CLOCK_THREAD_CPUTIME_ID   3
#define POSIX_CLOCK_MONOTONIC_RAW       4

#if CLOCK_REALTIME == POSIX_CLOCK_MONOTONIC
    #warning This platform has monotonic realtime clock.
#end if
#if CLOCK_MONOTONIC == POSIX_CLOCK_MONOTONIC_RAW
    #warning This platform has undisciplined monotonic clock.
#end if

If a system actually supports CLOCK_TAI but does not define it in time.h, how can I check and use that, taking into account that the same numeric value 11 may stand for CLOCK_MONOTONIC_PRECISE or whatever in other systems?

1

There are 1 best solutions below

2
On

If I was trying to write a maximally-portable program, I would limit myself to the symbolic values defined in the relevant Standard. (From what you say, it sounds like CLOCK_REALTIME -- and perhaps only that value -- is standard.)

If some systems implement useful extensions that I wanted to use, I would test for them by saying

#ifdef CLOCK_MONOTONIC_COARSE
... my code calling clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) ...
#endif

And if it's really true that there are systems out there where the same symbolic values end up meaning distinctly different things, I would throw up my hands and declare that to be a portability nightmare, the kind that I, at least, try to stay far away from.

In answer to your other questions, (1) no, it's not wise to make assumptions about the symbolic values, and (2) there's no good way to use a clock that somehow does exist but is not defined in time.h (though this situation would hopefully be quite rare).

Also, are you assuming that just because the numeric value 1 is used for CLOCK_MONOTONIC on Linux but for CLOCK_REALTIME under Cygwin means that those clocks might somehow be the same? That's probably not the case. The numbers are arbitrary and you shouldn't care about them; that's why the symbolic constants exist!