Linux time 64 bit

Linux time 64 bit

In the Linux kernel, in order to be compatible with the original code,Or meet certain specifications,And also to meet the current requirements of increasing accuracy,A variety of data structures related to time but used for different purposes are implemented:

1) jiffies and jiffies_64

The kernel uses the jiffies_64 global variable to record how many ticks the system has passed since it was started. Its declaration is as follows (the code is located in kernel/time/timer.c):

__visible u64 jiffies_64 __cacheline_aligned_in_smp=initial_jiffies; export_symbol (jiffies_64); 

It can be seen that jiffies_64 is defined as a 64-bit unsigned integer.However, for historical reasons,The kernel source code also contains another variable called jiffies. The quote of jiffies (the code is in include/linux/jiffies.h) states:

extern u64 __cacheline_aligned_in_smp jiffies_64; extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies; 

Therefore, the jiffies variable is a global variable of type unsigned long,If it is only 4 bytes long (32 bits) on a 32-bit processor. However, if it is also 8 bytes long (64 bits) on a 64-bit processor, then the two global variables jiffies and jiffies_64 are completely equivalent.

But through all the code, you can’t find the definition of the global variable jiffies, and finally found the following line in the kernel link script (for arm64 architecture, the script is located in arch/arm64/kernel/vmlinux.lds.s):

The mystery is here,It was originally specified that the symbols jiffies and jiffies_64 point to the same address when linking.In other words,On 32-bit machines,The lower 4 bytes of jiffies and jiffies_64 are the same.

In general,Whether on a 32-bit or 64-bit machine,We can all directly access jiffies global variables,But if i want to get the jiffies_64 global variable,You need to call the get_jiffies_64 function. For 64-bit systems,Both are the same,And jiffies are declared to be volatile and cache aligned, so just return jiffies directly:

static inline u64 get_jiffies_64 (void)

For 32-bit systems,Since it is not atomic for 64-bit reading and writing,So you still need to hold the jiffies_lock read order lock:

u64 get_jiffies_64 (void) < unsigned int seq; u64 ret; do < seq=read_seqbegin (&jiffies_lock); ret=jiffies_64; >while (read_seqretry (&jiffies_lock, seq)); return ret; > 

Basically, jiffies will increase by 1 every time the tick comes, and the tick period hz is configured by the kernel compilation options.In a 32-bit system,We assume that hz is set to 250, then each tick period is 4 milliseconds, then the counter will overflow after reaching the maximum after less than 200 days.If hz is set higher,Then this overflow time will be shorter.Of course, if you are on a 64-bit system,You don’t need to consider this issue at all.Therefore, when using jiffies for time comparison,You need to use several macros that have been defined by the system:

time_after (a, b) time_before (a, b) time_after_eq (a, b) time_before_eq (a, b) time_in_range_open (a, b, c) time_is_before_jiffies (a) time_is_after_jiffies (a) time_is_before_eq_jiffies (a) time_is_after_eq_jiffies (a) 

For insurance,The kernel also provides a corresponding 64-bit version. These macros can effectively solve the rewind problem,But it is not unlimited.How does it work?We pick a time_after macro and take a look at it:

#define time_after (a, b) \ (typecheck (unsigned long, a)&&\ typecheck (unsigned long, b)&&\ ((long) ((b)-(a))<0)) 

First, do type checking on the two variables,Must be all unsigned long. The most important thing is the back,First subtract the two unsigned long integers,Then turn them into signed long integers,Then determine whether it is negative,That is, whether the highest bit of 32 bits is 1.

Читайте также:  Astra linux special edition инструкции

Why can this partially solve the so-called rewind problem?We can give an example,For simplicity,Take 8-bit unsigned integer as an example,The value range is 0 to 255 (0xff). Assuming the current time is 250, then after 5 ticks, it is 255, which has reached the maximum value that can be expressed.At this time, if there is another tick, that is, 6 ticks, the overflow will become 0. At this time, if we simply judge which time is later by comparing the two values,Obviously something is going wrong,Because the time after 6 ticks is 0, but it is less than the current time,This problem is called rewinding.However, if we subtract these two numbers first,That is, 0-250 (0-0xfa) will also overflow,The final number is exactly 6. But this is also limited,The difference between the two comparison times cannot exceed half of the maximum representation range.Assuming that the current time is still 250, and after 128 ticks, the time value will become 122. If the two are subtracted, it will be 122-250 (0x86-0xfa). The subtracted number is 128. Becomes a signed number and becomes a negative number,The result is wrong.

In addition, jiffies are updated once per tick,The tick period is defined at compile time,So you can convert the value of jiffies into how much time has passed,vice versa.Therefore, the kernel provides the following conversion functions:

unsigned int jiffies_to_msecs (const unsigned long j); unsigned int jiffies_to_usecs (const unsigned long j); unsigned long msecs_to_jiffies (const unsigned int m); unsigned long usecs_to_jiffies (const unsigned int u); 

2) timespec and timespec64

timespec consists of seconds and nanoseconds,Its definition is as follows (the code is located in include/uapi/linux/time.h):

tv_sec:stores the number of seconds that have passed since 0:00 (UTC time) on January 1, 1970.__kernel_time_t is finally defined as a long type, which is 32 bits long on 32-bit systems and 64 bits long on 64-bit systems.

tv_nsec:stores the number of nanoseconds (ns) that have passed since the last second.

timespec also has a 64-bit extended structure,Its definition is as follows (code is located in include/linux/time64.h):

typedef __s64 time64_t; . struct timespec64 < time64_t tv_sec; long tv_nsec; >; 

The variable definition in this structure is the same as timespec, except that the type of tv_sec must be a 64-bit unsigned number.So, that is to say, on 64-bit systems,The timespec and timespec64 structures are identical.

Читайте также:  Xsane linux невозможно открыть устройство

In the time subsystem of linux,Generally use ktime_t to represent time,Its definition is as follows (the code is located in include/linux/ktime.h):

Is a very simple 64-bit signed integer,The time unit indicated is nanoseconds.

The gettimeofday and settimeofday functions use timeval as the time unit:

tv_sec:stores the number of seconds that have passed since 0:00 (UTC time) on January 1, 1970.__kernel_time_t is finally defined as a long type, which is 32 bits long on 32-bit systems and 64 bits long on 64-bit systems.

tv_usec:__kernel_suseconds_t is actually defined as a long type, and stores the number of microseconds (us) that have passed since the last second.

Therefore, this structure is actually similar to the timespec structure,The value stored in tv_sec is the same,And only need to divide tv_nsec in timespec by 1000 is tv_usec in timeval.

Источник

Is there any way to get 64-bit time_t in 32-bit programs in Linux?

Not really. on 32-bit Linux, time_t is a traditional 32-bit signed quantity, with only 25 years of useful life left in it. On 64-bit Unix systems, it is already a 64-bit quantity. If you want a portable type, you'll have to define your own that maps appropriately, or just use time_t carefully. The other question referenced has relevant information (but I agree it is not a duplicate).

5 Answers 5

Many answers above said that this is impossible, but that's entirely incorrect. It was not possible at that time yet people had been talking about fixing it for years. Finally 64-bit time support on 32-bit platforms was introduced to the Linux 5.1 kernel with the addition of the new *time64 syscalls. Look at this table you can see that those syscalls are only available on 32-bit platforms. Now if you're writing code for 32-bit systems you can call clock_gettime64 directly (from inline assembly or C with syscall() ) to get the current time

However after that you're completely on your own. If you want full userspace support you must be on Linux 5.6 or higher along with musl 1.2+ or glibc 2.32+. Just rebuild your code and your time_t will become 64-bit long

  • All user space must be compiled with a 64-bit time_t , which will be supported in the coming musl-1.2 and glibc-2.32 releases, along with installed kernel headers from linux-5.6 or higher.
  • Applications that use the system call interfaces directly need to be ported to use the time64 syscalls added in linux-5.1 in place of the existing system calls. This impacts most users of futex() and seccomp() as well as programming languages that have their own runtime environment not based on libc.

Источник

Is there any way to get 64-bit time_t in 32-bit programs in Linux?

Apparently, no it's not possible. For starters, there is only one time() function in Linux, no time32() or time64() .

Читайте также:  Линукс минт начало работы

After searching for a while, I can see that it's not libc's fault, but the culprit is actually the kernel.

In order for libc to fetch the current time, it need to execute a system call for it: (Source)

The system call is defined as: (Source)

SYSCALL_DEFINE1(time, time_t __user *, tloc) < time_t i = get_seconds(); // . return i; >

The function get_seconds() returns an unsigned long , like so: (Source)

unsigned long get_seconds(void) < struct timekeeper *tk = &timekeeper; return tk->xtime_sec; > 

And timekeeper.xtime_sec is actually 64-bit: (Source)

Now, if you know your C, you know that the size of unsigned long is actually implementation-dependant. On my 64-bit machine here, it's 64-bit; but on my 32-bit machine here, it's 32-bit. It possibly could be 64-bit on some 32-bit implementation, but there's no guarantee.

On the other hand, u64 is always 64-bit, so at the very base, the kernel keeps track of the time in a 64-bit type. Why it then proceeds to return this as an unsigned long , which is not guaranteed to be 64-bit long, is beyond me.

In the end, even if libc's would force time_t to hold a 64-bit value, it wouldn't change a thing.

You could tie your application deeply into the kernel, but I don't think it's even worth it.

Many answers above said that this is impossible, but that's entirely incorrect. It was not possible at that time yet people had been talking about fixing it for years. Finally 64-bit time support on 32-bit platforms was introduced to the Linux 5.1 kernel with the addition of the new *time64 syscalls. Look at this table you can see that those syscalls are only available on 32-bit platforms. Now if you're writing code for 32-bit systems you can call clock_gettime64 directly (from inline assembly or C with syscall() ) to get the current time

However after that you're completely on your own. If you want full userspace support you must be on Linux 5.6 or higher along with musl 1.2+ or glibc 2.32+. Just rebuild your code and your time_t will become 64-bit long

  • All user space must be compiled with a 64-bit time_t , which will be supported in the coming musl-1.2 and glibc-2.32 releases, along with installed kernel headers from linux-5.6 or higher.
  • Applications that use the system call interfaces directly need to be ported to use the time64 syscalls added in linux-5.1 in place of the existing system calls. This impacts most users of futex() and seccomp() as well as programming languages that have their own runtime environment not based on libc.
  • Approaching the kernel year-2038 end game
  • 64-bit time symbol handling in the GNU C Library
  • glibc Y2038 Proofness Design
  • Change time_t and clock_t to 64 bit

Источник

Оцените статью
Adblock
detector