Typically, the operating system can use three methods to represent the current time and date of the system:
The simplest method of ① is to count the clock ticks directly with a 64-bit counter.
② the second method is to use a 32-bit counter to count the seconds, while also using a 32-bit auxiliary counter to the clock tick count, the child accumulates to one second. Because 232 is more than 136 years old, this method can work well for the system until 22nd century.
③ The third method is also counted by clock ticks, but is not relative to a definite external moment relative to the time of the system startup, but the current time is calculated based on the current tick count, when the external fallback clock (such as RTC) is read or when the user enters actual times.
UNIX class operating systems typically use a third method to maintain the system's time and date.
1 Basic Concepts
First, it is necessary to identify some basic concepts in the Linux kernel clock driver.
(1) Frequency of clock cycle: 8253/8254 The essence of the pit is to count the clock cycles generated by the crystal oscillator, and the number of clock pulses produced by the crystal oscillator in 1 seconds is the frequency of the clock cycle.
Linux uses macro clock_tick_rate to represent the frequency of input clock pulses in the 8254 pit (typically 1193180HZ in a PC), which is defined in the Include/asm-i386/timex.h header file:
#define CLOCK_TICK_RATE 1193180/* Underlying HZ */
(2) Clock tick: We know that when the counter of pit Channel 0 is reduced to a value of 0, it generates a clock interrupt on the IRQ0, which is the clock tick. The initial value of the counter for pit channel 0 determines how many clock cycles are needed to produce a single clock break, thus determining the interval length of a clock tick.
(3) clock tick frequency (HZ): The number of clock ticks generated by the pit in the 1 second time. Similarly, this value is determined by the counter value of pit Channel 0 (conversely, the value of the counter of the 8254 pit Channel 0 can be determined after determining the frequency of the clock tick). The Linux kernel uses the macro Hz to represent the frequency of clock ticks, and the Hz has different defined values on different platforms. The value for the Alpha and IA62 platform Hz is 1024, and the value for platform Hz, such as SPARC, MIPS, arm, and i386, is 100. The macro is defined on the i386 platform as follows (INCLUDE/ASM-I386/PARAM.H):
#ifndef HZ
#define HZ 100
#endif
Depending on the value of HZ, we can also know that the specific time interval of a clock tick should be (1000ms/hz) =10ms.
(4) Clock tick interval: Linux uses the global variable tick to represent the time interval length of the clock tick, which is defined in the Kernel/timer.c file as follows:
Long tick = (1000000 + hz/2)/HZ; /* Timer Interrupt Period */
The unit of the tick variable is subtle (μs), because the value of the macro Hz differs on different platforms, so the result of the equation tick=1000000÷hz may be a decimal, so it is rounded to an integer, So Linux defines the tick as (1000000+HZ/2)/hz, where the HZ/2 in the dividend expression is used to round the tick value up into an integer number.
In addition, Linux also uses the macro tick_size as the reference alias (alias) of the Tick variable, which is defined as follows (ARCH/I386/KERNEL/TIME.C):
#define Tick_size TICK
(5) Macro Latch:linux uses the macro latch to define the value to be written to the counter in pit Channel 0, which indicates that the pit will produce a clock interrupt with no more than the number of clock cycles. Obviously latch should be calculated by the following formula:
Latch= (number of clock cycles within 1 seconds) ÷ (number of clock interrupts within 1 seconds) = (clock_tick_rate) ÷ (HZ)
Similarly, the result of the above formula may be a decimal, which should be rounded. So, Linux defines latch as (include/linux/timex.h):
/* LATCH is used in the interval timer and ftape setup. */
#define LATCH ((clock_tick_rate + HZ/2)/HZ)/* for divider */
Similarly, the HZ/2 in the divisor expression is also used to round the latch up into an integer.
2 kernel data structure representing the current time of the system
As a UNIX class operating system, the Linux kernel obviously uses the third method described at the beginning of this section to represent the current time of the system. The Linux kernel uses three important data structures to represent the current time of the system:
① global variable jiffies: This is a 32-bit unsigned integer that represents the number of clock ticks since the last boot of the kernel. Each time a clock tick occurs, the kernel's clock interrupt handler function Timer_interrupt () adds the global variable jiffies to 1. The variable is defined in the KERNEL/TIMER.C source file as follows:
unsigned long volatile jiffies;
The C-Language qualifier volatile means that jiffies is a variable that is easy to change, so the compiler will make access to the variable never through the internal CPU cache.
② global variable Xtime: It is a variable of timeval struct type that represents the relative second value of the current time base 1970-01-01 00:00:00 of Unix time. Structure Timeval is a format for the Linux kernel to represent time (the Linux kernel has multiple formats for time representation, each with a different time accuracy), and its time accuracy is microseconds. This structure is the most commonly used format when the kernel represents time, and it is defined in the header file Include/linux/time.h as follows:
struct Timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
Where the member Tv_sec represents the current time from the Unix time base of the second value, and the member Tv_usec represents the Microsecond value within one second, and 1000000>tv_usec>=0.
The Linux kernel maintains the current time by timeval the global variable xtime of the struct type, which is defined in the Kernel/timer.c file as follows:
/* The current time */
volatile struct Timeval xtime __attribute__ ((aligned (16)));
However, the current time that global variable xtime is maintained is usually for the user to retrieve and set, while other kernel modules often use it very infrequently (other kernel modules use the most jiffies), so updating the xtime is not an urgent task. So this work is usually deferred to the bottom half of the clock interrupt (bottom half). Since the execution time of the bottom half is uncertain, in order to remember when the kernel last updated xtime, the Linux kernel defines a jiffies-like global variable wall_jiffies, To save the Jiffies value at the time the kernel updated xtime. The bottom half of the clock interrupt updates the wall_jiffies to the Jiffies value at the time each time the Xtime is updated. The global variable wall_jiffies is defined in the Kernel/timer.c file:
/* Jiffies at the most recent update of wall time */
unsigned long wall_jiffies;
③ global variable Sys_tz: It is a global variable of a timezone struct type that represents the current time zone information for the system. The struct type timezone is defined in the Include/linux/time.h header file as follows:
struct TimeZone {
int tz_minuteswest; /* minutes west of Greenwich * *
int tz_dsttime; /* Type of DST correction */
};
Based on the above structure, Linux defines the global variable Sys_tz in the kernel/time.c file to represent the current time zone information for the system, as shown here:
struct timezone Sys_tz;
More wonderful Linux video tutorials at 51CTO Academy: http://edu.51cto.com/course/courseList/id-48.html
Time in the Linux world