一直以来对Linux下的时间管理知之不详,GFree_wind在微博发起过几次Linux下时钟的讨论,和Godbach这些大牛比,我完全插不上话,因为不懂。近来闲暇时间研究了下Linux下的时间管理,分享出来,请大家指正。
从我们大白话的角度想,时间管理其实分成两部分,就像我们小时候学习物理的时候物理老师不断强调时间和时刻的区别。一个是时刻,比如现在是20:44:37秒,指的是时刻,我们手机上看时间,指的也是时刻。另一块是时间,比如说,我每天工作八小时,再比如说,半小时之后,我要出门了,结束时间指向的是未来,但是仍然是一段时间。OK。无论是时刻还是时望间,都是需要硬件支持的,你手里只有一块最小刻度只有1秒的手表,就不要指用这块手表给百米大赛度量成绩了,何哉,硬件太挫。Linux也是如此,之所以Linux启动之后,可以精确的计时,那是因为Linux的下面有相应的硬件为依托。
RTC
RTC,real time clock,实时时钟和其他的硬件是不同的,RTC吐出来的是时刻,而其他硬件时钟吐出来的是时间。也就是说,RTC能告诉我们,当前是2013年9月12日,21:49:38,但是其他的硬件如TSC,PIT,HPET只能告诉我们,我应该走过了XX个cycle,按照我的频率,已经过去了10分钟了。
为啥RTC这么牛X,可以告诉我们当前时刻,哪怕用户关了机?以X86为例,RTC是主板上的一块CMOS芯片,哪怕你的Linux关了机,她也可以依赖主板上的电池维持时钟的准确。当然了,在Linux下,RTC存储的是UTC时间,而不会考虑timezone。
所以,Linux启动的时候,一定会拜访RTC来获得当前的时刻值,尽管精度不高(精确到秒)。When and How?
首先回答When。Linux启动的时候,start_kernel有四大time相关的函数调用:
init_timers();
hrtimers_init();
timekeeping_init()
time_init();
从RTC中读取当前的UTC时间是timekeeping_init中做的事情,调用路径如下:
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, }
对于我们而言,我们要读的function是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); }
这一段代码已经牵扯到了硬件相关的编程,我们其实并不关心驱动,对于硬件比较感兴趣的筒子,可以访问http://xenyinzen.wikidot.com/reship:080225-2
获得更多更详细的信息。mktime是将年月日时分秒组装成1970年1月1日00:00:00这个UNIX基准时间以来的秒数。我们在Linux下可以通过一下方式获得这个值:
root@manu:/sys/class/rtc/rtc0# date +%s ;cat /sys/class/rtc/rtc0/since_epoch 1379081060 1379081060
既然Linux上电的时候,可以从RTC中读出当前的时间,我们也可以设置时间,并且写入到RTC。用户层也可以操作RTC硬件时钟,通过ioctl。下面给出一个样例:
#include #include #include #include #include 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; }
输出如下:
root@manu:~/code/c/self/rtc# ./rtc_test RTC time is 2013-8-14 15:46:2
对于set RTC 也可以通过ioctl RTC_SET_TIME参数来实现,我就不多说了,对这部分感兴趣的,可以自行man rtc,或者Kernel的Documentation/rtc.txt有一个示例代码,比较详细。
已经说过了,RTC在时间相关的硬件中是个独树一帜的奇葩,作用和其他的硬件不同。而其他的硬件只是以一定的频率产生时钟中断,帮助OS完成计时。前面我也提到过,你手里拿着个手表,就不要指望给百米大赛计时,原因就是精度太低。硬件也是如此,有精度高的有精度低的。Linux操作系统抽象出了clocksource(时钟源)来管理这些硬件。Linux会在所有的硬件时钟中选择出精度最高作为当前在用的时钟源。
如何查看当前所有的可用的时钟源已经当前在用的时钟源呢?
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
相关推荐
在Linux中,时间主要分为两类:系统时间(System Time)和硬件时钟(Hardware Clock)。系统时间是操作系统维护的时间,用于所有进程的计时,可以通过`date`命令查看。硬件时钟则是计算机BIOS中保存的时间,通常与...
### Linux NTP时间同步设置详解 #### 一、概述 在Linux系统中,时间的准确性对于许多服务至关重要,比如日志记录、定时任务等。为了确保时间的精确性,...希望这些方法能够帮助大家更好地管理Linux系统的时间设置。
在Linux系统中,定时器(Timer)是一种非常重要的机制,它允许程序在特定的时间间隔后执行某些操作。本文将深入探讨“基于Linux定时器管理器”的相关知识点,包括定时器的类型、工作原理以及如何添加、删除定时器,...
在Linux中,有两个重要的时间源:系统时钟(System Clock)和硬件时钟(Hardware Clock)。系统时钟是操作系统运行时所用的时间,而硬件时钟是主板上的一个独立芯片,即使系统关闭,它仍然可以保持时间。在开发板上...
在Linux系统中,时间管理是一项重要的任务,因为它不仅关乎到系统的正常运行,还与网络通信、数据同步以及日志记录紧密相关。本文将详细讲解如何在Linux系统中修改和同步系统时间,以及相关的知识点。 首先,Linux...
本PPT将深入探讨Linux内核的时间管理机制,帮助我们理解其工作原理和重要功能。 在Linux内核中,时间主要由两部分组成:硬件时钟(Hardware Clock)和系统时钟(System Clock)。硬件时钟是计算机内部的一个物理...
在Zynq平台上运行Linux时,中断处理是操作系统与硬件交互的关键机制之一,特别是对于时间管理,timer中断起着至关重要的作用。本篇将详细探讨Zynq-Linux中的timer中断源码以及axi-timer的相关知识。 首先,让我们...
在Linux系统中,PTP被广泛应用于各种需要精确时间同步的场景,如数据中心、金融交易、通信网络等。本资源包含PTP协议在Linux上的运行源代码,分为版本1和版本2,其中版本2在性能和功能上进行了优化。 PTP协议的核心...
总的来说,这个实验报告旨在提升学生在Linux环境下的实际操作能力和解决问题的能力,为未来进行更复杂的系统管理和开发工作奠定坚实基础。通过这样的实践,学生能够更好地理解和应用Linux系统,提高软件工程的实践...
Linux内核通过定时器来实现精确的时间管理。**系统定时**机制主要包括: 1. **定时器中断**:通过硬件定时器(如Intel 8253)每隔一定时间(通常是10毫秒)触发中断,这个时间单位被称为**系统滴答**。 2. **时钟...
1. **基础概念:** 首先介绍了Linux内核的基础知识,包括内核模块、进程管理、内存管理等关键概念,为后续章节的学习打下坚实的基础。 2. **字符设备驱动:** 详细讲解了如何开发字符设备驱动,涵盖了设备注册、输入...
本主题聚焦于如何利用Qt获取计算机的CPU信息,这是一个常见的需求,特别是在系统监控、性能分析或者资源管理软件的开发中。下面我们将深入探讨如何在Qt中实现这一功能,并考虑在Linux和Windows平台上的差异。 在...
在Linux系统中,**调度器(scheduler)**是核心组件之一,它负责管理和分配CPU资源给不同的进程和中断。调度器通过设置不同资源的优先级来确保系统高效运行。 1. **硬件中断(Hardware Interrupts):** - **定义:** ...
本书还推荐了一些O’Reilly出版的其他Linux资源,包括《Designing Embedded Hardware》、《Linux Device Drivers》、《Linux in a Nutshell》以及《Linux Network Administrator’s Guide》等,这些都是在嵌入式...
5. **kernel**:Linux内核是Android系统的基础,它负责管理系统的硬件资源,包括CPU、内存、I/O设备等。内核提供了系统调用接口,让上层软件能够访问硬件功能和执行低级操作。例如,通过系统调用,应用程序和服务...
总之,Linux定时器是系统内核中一个非常关键且功能强大的组件,它不仅支持了系统的基本时间管理和任务调度,还为开发者提供了灵活的工具来实现复杂的时间控制需求。通过对定时器的合理利用,可以极大地提高系统的...
RTAI通过定义一组RTHAL(Real-Time Hardware Abstraction Layer)来隔离底层硬件与实时系统,使得移植工作更加简单。 #### 4. 实时Linux操作系统实现步骤 ##### 4.1 安装Linux操作系统 首先,在计算机上安装一个...
2. **Linux内核定时器接口**:在Linux内核中,开发者可以使用`struct timer_list`结构来创建和管理定时器。这个结构包含定时器的函数指针,当定时器到期时,该函数会被调用。`setup_timer()`和`add_timer()`等函数...
### Linux驱动开发之S3C2440按键点亮LED #### 一、驱动开发流程与背景 在进行Linux驱动开发之前,理解整个流程是非常重要的。驱动开发与应用程序开发不同,它更偏向底层,直接与硬件交互。通过操作硬件并为上层...