I have never known much about Linux time management. GFree_wind has been discussing Linux clock several times on Weibo. Compared with Godbach, I can't talk about it because I don't understand it. Recently, I have studied time management in Linux in my spare time and shared it with you. please correct me.
From our perspective, time management is divided into two parts, just as when we were a child, physics teachers constantly stressed the difference between time and time. One is time. For example, the current time is 20:44:37. It refers to the time. We can see the time on our mobile phone. It also refers to the time. The other part is time. For example, I work eight hours a day. For example, after half an hour, I want to go out. The end time is about the future, but it is still a period of time. OK. Hardware support is required for both time and time frames. If you have only one watch with a minimum scale of 1 second in your hand, do not use this watch to measure the score for the-meter competition, he Zai, hardware is too frustrating. This is also true for Linux. The reason why Linux enables accurate timing after it is started is because the corresponding hardware in Linux is supported.
RTC
RTC, real time clock, real-time clock is different from other hardware. RTC uses time, while other hardware uses time. That is to say, RTC can tell us that the current time is September 12, 2013 21:49:38, but other hardware such as TSC, PIT, and HPET can only tell us that I should have passed XX cycle, according to my frequency, it has been 10 minutes.
Why is RTC so cool? Can you tell us the current time, even if the user is shut down? Taking X86 as an example, RTC is a CMOS chip on the motherboard. Even if your Linux is shut down, she can rely on the battery on the motherboard to maintain accurate clock. Of course, in Linux, RTC stores UTC time instead of timezone.
Therefore, when Linux is started, it will definitely visit RTC to obtain the current time value, although the accuracy is not accurate to seconds ). When and How?
Answer When first. When Linux is started, start_kernel has four time-related function calls:
Reading the current UTC time from RTC is done in timekeeping_init. The call path is as follows:
| Timekeeping_init | ___________ Read_persistent_clock (arch/x86/kernel/rtc. c) | _____ X86_platform.get_wallclock () | _____ Mach_get_cmos_time (arch/x86/kernel/x86_init.c) |
- /************arch/x86/kernel/rtc.c*****************/
- void read_persistent_clock(struct timespec *ts)
- {
- unsigned long retval;
-
- retval = x86_platform.get_wallclock();
-
- ts->tv_sec = retval;
- ts->tv_nsec = 0;
- }
-
- /*****************arch/x86/kernel/x86_init.c ****************/
-
- struct x86_platform_ops x86_platform = {
- .calibrate_tsc = native_calibrate_tsc,
- .wallclock_init = wallclock_init_noop,
- .get_wallclock = mach_get_cmos_time,
- .set_wallclock = mach_set_rtc_mmss,
- .iommu_shutdown = iommu_shutdown_noop,
- .is_untracked_pat_range = is_ISA_range,
- .nmi_init = default_nmi_init,
- .get_nmi_reason = default_get_nmi_reason,
- .i8042_detect = default_i8042_detect,
- .save_sched_clock_state = tsc_save_sched_clock_state,
- .restore_sched_clock_state = tsc_restore_sched_clock_state,
- }
For us, the function we want to read is mach_get_cmos_time.
- unsigned long mach_get_cmos_time(void)
- {
- unsigned int status, year, mon, day, hour, min, sec, century = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
-
- /*
- * If UIP is clear, then we have >= 244 microseconds before
- * RTC registers will be updated. Spec sheet says that this
- * is the reliable way to read RTC - registers. If UIP is set
- * then the register access might be invalid.
- */
- while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
- cpu_relax();
-
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
-
- #ifdef CONFIG_ACPI
- if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
- acpi_gbl_FADT.century)
- century = CMOS_READ(acpi_gbl_FADT.century);
- #endif
-
- status = CMOS_READ(RTC_CONTROL);
- WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
-
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
- sec = bcd2bin(sec);
- min = bcd2bin(min);
- hour = bcd2bin(hour);
- day = bcd2bin(day);
- mon = bcd2bin(mon);
- year = bcd2bin(year);
- }
-
- if (century) {
- century = bcd2bin(century);
- year += century * 100;
- printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
- } else
- year += CMOS_YEARS_OFFS;
-
- return mktime(year, mon, day, hour, min, sec);
- }
This piece of code has involved hardware-related programming, we are not actually concerned about the driver, for the hardware is more interested in the package, you can access the http://xenyinzen.wikidot.com/reship:080225-2
For more details. Mktime is the number of seconds since the UNIX benchmark time of January 1, 1970 00:00:00. In Linux, we can obtain this value through the following method:
- root@manu:/sys/class/rtc/rtc0# date +%s ;cat /sys/class/rtc/rtc0/since_epoch
- 1379081060
- 1379081060
Since the current time can be read from RTC during Linux power-on, we can also set the time and write it to RTC. The user layer can also operate the RTC hardware clock through ioctl. The following is an example:
- #include <stdio.h>
- #include <stdlib.h>
- #include <linux/rtc.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
-
- int main(int argc,char *argv[])
- {
- int retval,fd;
- struct rtc_time rtc_tm;
-
- fd=open("/dev/rtc",O_RDONLY);
- if(fd==-1)
- {
- perror("error open /dev/rtc");
- return -1;
- }
-
- retval=ioctl(fd,RTC_RD_TIME,&rtc_tm);
- if(retval==-1)
- {
- perror("error exec RTC_RD_TIME ioctl");
- return -2;
- }
- printf("RTC time is %d-%d-%d %d:%d:%d \n",
- rtc_tm.tm_year+1900,rtc_tm.tm_mon,rtc_tm.tm_mday,
- rtc_tm.tm_hour,rtc_tm.tm_min,rtc_tm.tm_sec);
-
- close(fd);
-
- return 0;
- }
The output is as follows:
- root@manu:~/code/c/self/rtc# ./rtc_test
- RTC time is 2013-8-14 15:46:2
For set RTC, you can also use the ioctl RTC_SET_TIME parameter. I will not talk about it much. If you are interested in this part, you can use man rtc or the Documentation/rtc.txt of the Kernel to have a sample code, more detailed.
As we have already said, RTC is a unique time-related hardware. Its role is different from that of other hardware. Other hardware only generates clock interruptions at a certain frequency, helping the OS to complete timing. As I mentioned earlier, if you have a watch in your hand, you should not count on timing the hundred meters competition because the precision is too low. The same is true for hardware, with high precision and low accuracy. Linux abstracts the clocksource clock source) to manage these hardware. Linux selects the highest accuracy among all hardware clocks as the currently used clock source.
How can I view all currently available clock sources that are currently in use?
- manu@manu:/$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
- tsc hpet acpi_pm
- manu@manu:/$ cat /sys/devices/system/clocksource/clocksource0/current_clocksource
- tsc
We will introduce hpet, acpi_pm, and tsc respectively, but before that, we will introduce a PIT