|
|
Subscribe / Log in / New account

Year 2038 preparations in 3.17

By Jonathan Corbet
August 6, 2014
January 19, 2038 is, of course, that fateful date when 32-bit time_t variables wrap around, bringing about the end of time as Unix-like systems know it. Though 2038 may seem far away, it is not too soon to be worrying about this problem; code needs to be able to work with future dates, and some systems being deployed now will certainly still be around 24 years from now. A full solution to the problem of keeping 32-bit systems working in 2038 is going to take a while to reach. But some of the first baby steps in that direction were taken during the 3.17 merge window.

Much of the work involves changes to two structures used within the kernel: union ktime (usually referred to as ktime_t) and struct timespec. The ktime_t structure was introduced with the high-resolution timer patch set back in 2006; it is meant to be an opaque type for the storage of time values within the kernel. Indeed, it is sufficiently opaque that its definition varies widely depending on the underlying architecture.

For 64-bit systems, ktime_t has always been a simple integer count of nanoseconds. This "scalar" format is easy to manipulate and perform arithmetic on — as long as the CPU has fast 64-bit operations. Since such operations tend to be absent on 32-bit systems, ktime_t has often been defined differently there; it is represented as a structure with separate, 32-bit fields for seconds and nanoseconds. Kernel code uses a set of accessor functions for working with ktime_t values, so the difference in representation is well hidden and does not affect how the rest of the kernel works.

That difference will be rather less well hidden in 2038, though, when the 32-bit seconds field overflows with all the rest. So, for things to keep working in 2038, the ktime_t structure will have to change. One of the first changes merged for 3.17 is to simply get rid of the non-scalar form of ktime_t and force all architectures to use the 64-bit nanosecond count representation. This change may slow things down on 32-bit systems; in particular, conversions from other time formats may be significantly slower. But, as noted in the changelog, the ARM and x86 architectures were already using the scalar format anyway, so they will not get any slower.

Regardless of whether conversions between ktime_t and other formats are fast or not, avoidance of those conversions when possible seems like a promising way of optimizing code within the kernel. The 3.17 changes include a number of time-format changes within various kernel subsystems, causing them to just work with straight nanosecond time values. The result is generally a simplification of the code and, presumably, faster execution.

The other time-related structure used heavily within the kernel is struct timespec:

    struct timespec {
	__kernel_time_t	tv_sec;			/* seconds */
	long		tv_nsec;		/* nanoseconds */
    };

The __kernel_time_t type is just another name for time_t in current kernels; it is, thus, a 32-bit value on 32-bit systems. Unlike ktime_t, though, struct timespec cannot just be changed; it is used in user space as well and is a part of the kernel's ABI. What has been done instead in 3.17 is to add a new structure:

    struct timespec64 {
	time64_t	tv_sec;			/* seconds */
	long		tv_nsec;		/* nanoseconds */
    };

On 64-bit systems, this structure is identical to struct timespec. Within the core timekeeping code, every struct timespec has been changed to be struct timespec64 instead. The interfaces providing access to timekeeping functionality to the rest of the kernel have been tweaked to hide this change (so far), and a new set of interfaces has been added for code that is using struct timespec64. After this change, there are no more time values using 32-bit seconds counts in the timekeeping core.

The result of all this work is a long way from a solution to the year-2038 problem. But it is one important step in that direction: the core timekeeping code within the Linux kernel will no longer have problems when 2038 rolls around. With a couple more steps, a full solution to the problem may well be in sight. The first of those steps is to push use of struct timespec64 outward from the timekeeping core into the rest of the kernel. This task may involve a fair amount of work, but it is an example of the sort of evolutionary change that the kernel community is relatively good at. Given a bit of time, kernel code should be almost entirely free of year-2038 issues.

The harder step, of course, is to incorporate year-2038-safe structures into the kernel ABI and get user-space developers to change their code over. That will require cooperation with user-space developers from the C-library level on up and a lot of thought into how this change can be made with a minimum of pain. One should not expect it to happen quickly. But the problem is now well established on the radar of many of the relevant developers, so the chances of resolving most of the problems without a last-minute panic seem to be reasonably good. The first steps have been taken; hopefully the rest will follow before too long.

Index entries for this article
KernelYear 2038 problem


to post comments

Year 2038 preparations in 3.17

Posted Aug 7, 2014 4:15 UTC (Thu) by brouhaha (subscriber, #1698) [Link] (10 responses)

One of the first changes merged for 3.17 is to simply get rid of the non-scalar form of ktime_t and force all architectures to use the 64-bit nanosecond count representation.
If my arithmetic is correct, that pushes the kernel time problem to December of 2554. I suppose I can't realistically complain about that being short-sighted, though I might have preferred having all architectures go to the non-scalar representation with 32 bit nanoseconds and 64 bit seconds, or even 64 bit attoseconds and 64 bit seconds. It's a shame that there isn't a uint128_t in the C standard.

Year 2038 preparations in 3.17

Posted Aug 7, 2014 7:53 UTC (Thu) by Villemoes (subscriber, #91911) [Link] (9 responses)

ktime_t uses s64, so the roll-over is "only" pushed to 2262. Maybe 128 bit architectures appear in the next 100 years, then there's still plenty of time to do the next transition.

Year 2038 preparations in 3.17

Posted Aug 7, 2014 15:03 UTC (Thu) by rriggs (guest, #11598) [Link] (1 responses)

It is possible that the notion of fixed-length native data types will be considered quaint by the time 2262 is near, just as the idea of fixed-width character sets is today.

Year 2038 preparations in 3.17

Posted Aug 7, 2014 19:37 UTC (Thu) by zlynx (guest, #2285) [Link]

Possible. But not likely.

I see it as more likely that everyone programs to a intermediate language like the LLVM or .NET IR instead of native machine code and that IR language uses infinite width data types.

By 2262 if we still program computers at all, we're probably writing in an abstraction layer that is many levels away from the real machine.

However, the real hardware is going to have a real number of wires, and the number of wires connected to the data bus is going to define the pointer size, and the number of gates built into the ALU is going to define the real native data word.

I suppose it is also possible that instead of bytes computers change to using bit streams because all of the data transport changes over to high-speed 1-bit serial. I am not quite sure how that would work, exactly, but I could imagine it.

Year 2038 preparations in 3.17

Posted Aug 8, 2014 3:41 UTC (Fri) by jstultz (subscriber, #212) [Link]

Also, ktime_t is that it is a kernel internal only type, so while we may have technically only kicked the can ~225 years out, any future generation of hackers who are tasked with fixing the Y2262 issue will be able to do it w/o the kernel abi issues we now face.

Year 2038 preparations in 3.17

Posted Aug 9, 2014 11:21 UTC (Sat) by Thue (guest, #14277) [Link] (5 responses)

> Maybe 128 bit architectures appear in the next 100 years, then there's still plenty of time to do the next transition.

It seems unlikely to me that 128 bit general purpose architectures will be built. There are simply so few places that need 128 bit integers that it is more efficient to emulate them when needed, like GCC's current __int128_t. And for addressing, 64 bit should be enough.

Year 2038 preparations in 3.17

Posted Aug 9, 2014 16:40 UTC (Sat) by Cyberax (✭ supporter ✭, #52523) [Link] (4 responses)

Well, 2^64 is close to 1 mole of bits. If we ever have near-atomic-density storage then it's not inconceivable that a computer might need more than 2^64 of addressable space.

2^128 seems to be safe, on the other hand. It's just not feasible to fill that much RAM with a classic computer.

Year 2038 preparations in 3.17

Posted Aug 11, 2014 13:38 UTC (Mon) by robbe (guest, #16131) [Link] (3 responses)

For some values of "close" ... Avogardo's number is in the 2^76 range.

If Moore's law holds for the next 50 years, we will see computers exhausting 64bit address space by then.

So we may run out of bits before we run out of fossile fuel to power this monsters.

Year 2038 preparations in 3.17

Posted Aug 11, 2014 14:46 UTC (Mon) by Cyberax (✭ supporter ✭, #52523) [Link] (2 responses)

Yes, it's not outrageously out of range. And you might still want to have more address space than actual addressable RAM.

As far as I remember, filling 2^64 bits requires _at_ _minimum_ enough energy to boil 10 liters of water. So these computers are definitely not going to be environment-friendly.

Year 2038 preparations in 3.17

Posted Aug 11, 2014 18:13 UTC (Mon) by dlang (guest, #313) [Link]

it all depends on how frequently you are refilling that memory, and how much other useful work gets done.

There's no amount of power usage that's automatically "environmentally unfriendly"

Year 2038 preparations in 3.17

Posted Aug 17, 2014 18:03 UTC (Sun) by Jandar (subscriber, #85683) [Link]

> As far as I remember, filling 2^64 bits requires _at_ _minimum_ enough energy to boil 10 liters of water.

I recall reading in a paper that there is no lower energy limit to *filling* memory, but there is a lower energy limit to *clear* memory since clearing restores order thus lowers entropy. Maybe with enough bits we can skip clearing and save energy with write-once memory :-).

Great news for all of us using Linux in embedded!

Posted Aug 7, 2014 15:49 UTC (Thu) by troglobit (subscriber, #39178) [Link]

This is truly great news for us in the embedded sector with support periods
ranking up to 30 years (!) -- not kidding. Some of us have tried to bring this issue up in the past, only to be shot down as proposing "band aid solutions".

I'm truly glad this is finally being addressed. People tend to only look to their desktop computers, or their phones being upgraded to use 64-bit processors, but the reality is that there's a HUGE embedded market going steady with 32-bit. And this will likely not change that much in the coming years.

The community has my deepest regards today, thank you so much! :)

Year 2038 preparations in 3.17

Posted Aug 8, 2014 14:15 UTC (Fri) by nix (subscriber, #2304) [Link]

This is a good start (reminiscent, surely intentionally, of the LFS approach) but of course doesn't solve problems in file formats or in filesystems themselves. 32-bit time_t's are still fairly common there :(

Year 2038 preparations in 3.17

Posted Aug 8, 2014 16:36 UTC (Fri) by josh (subscriber, #17465) [Link] (3 responses)

I wonder why we're enshrining a timespec64 type that still separates nanoseconds from seconds, necessitating manual carries and borrows when doing math, rather than just using a scalar number of nanoseconds or picoseconds. 2**64 nanoseconds only supports hundreds of years, but 2**128 nanoseconds (or picoseconds) would easily suffice. Systems that support direct math on 128-bit or larger values would handle it easily, and systems that don't can do the same kind of carry and borrow logic already needed for timespec or timespec64.

Year 2038 preparations in 3.17

Posted Aug 9, 2014 4:01 UTC (Sat) by jstultz (subscriber, #212) [Link] (2 responses)

First of all, for now the timespec64 is a kernel-internal only structure, so its not exactly enshrined at this point.

Secondly, timespecs are desired because quite often folks really just want seconds, not nanoseconds, so we internally in the kernel have to keep both ktime_t and timespec style structures for performance reasons.

Finally, depending on how we do the userspace interface changes, we may want to try to allow applications to possibly just be re-compiled to gain 2038 support, instead of requiring developers to rework the application to use new types. So preserving the timespec style will be important here. (Granted, this won't solve all the places applications store time in non-time_t related structures, but likely will go a long way.)

Year 2038 preparations in 3.17

Posted Aug 14, 2014 19:29 UTC (Thu) by spitzak (guest, #4593) [Link] (1 responses)

Why not count in some power of .5 rather than seconds or nanoseconds. I.e. use fixed-point. That makes arithmetic easy, and getting the number of seconds easy.

I sure don't like the idea that the timestruct is going to be 12 bytes rather than a power of 2.

A fixed-point system would be better, 1 sign bit + 33 integer bits + 30 bits fraction. That is in units of 1/1073741824 second, allowing all nanoseconds to have unique values. And if will be good until the year 2242. And it would use 8 bytes, the same size as the current structure.

Year 2038 preparations in 3.17

Posted Aug 14, 2014 19:49 UTC (Thu) by jwakely (subscriber, #60262) [Link]

NTP has a 64-bit fixed-point timestamp, see http://tools.ietf.org/html/rfc5905#section-6

> The 64-bit timestamp format is used in packet headers and other places with limited word size. It includes a 32-bit unsigned seconds field spanning 136 years and a 32-bit fraction field resolving 232 picoseconds.

Year 2038 preparations in 3.17 - why not use floating point?

Posted Aug 13, 2014 22:17 UTC (Wed) by rbthomas (subscriber, #39239) [Link] (2 responses)

Why not use 64-bit IEEE floating point? It has two very desirable properties:

1) it's fast on modern processors (even on fixed-point embedded processors there are highly optimized macros to perform floating point arithmetic)

2) It's "fail-soft" in that there is a trade-off between precision and larger numbers. It would give micro-second resolution for about 147 years before or after the epoch and milli-second resolution for 147,000 years, nano-second resolution for about 52 days, and pico-second resolution for a little over an hour.

If the epoch is the normal UNIX epoch of Jan 1, 1970, we would have micro-second resolution on timestamps between 1823 and 2117.

For time measurements that require nano- or pico- second resolution, you can define the epoch to be anything you want as long as you can measure it with that resolution. So if I set the epoch for a given set of computations to be the present moment, I can represent measurements over a period of 104 days at nanosecond or better resolution.

Year 2038 preparations in 3.17 - why not use floating point?

Posted Aug 14, 2014 9:01 UTC (Thu) by etienne (guest, #25256) [Link]

> why not use floating point?

Because that would mean managing floating point in the kernel, and that would mean saving/restoring the floating point registers at each task switch - instead of only when they have been used by the user-mode task...

Year 2038 preparations in 3.17 - why not use floating point?

Posted Aug 14, 2014 12:09 UTC (Thu) by JGR (subscriber, #93631) [Link]

What does going to 64 bit floating point give you that 64 bit seconds + nanoseconds does not?
Migrating to floating point would be far more painful than bumping an integer from 32 to 64 bits.

Being able to change the epoch at will, and being able to regularly update the clock with small increment ticks, imply storing the "master" value in some other higher-precision format, in which case you might as well just use that for everything.


Copyright © 2014, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds