linux 时间系统 一 时间相关的系统调用

时间相关的系统调用,这里主要说明的是用来记录时间(打时间戳)和delay时间的系统调用。它们是linux时间系统的一部分。 时间相关的操作在应用层和内核层都很重要。下面的代码基于linux-4.9内核, ARCH=mips
首先是两个比较重要的系统调用:
gettimeofday

#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz)
struct timeval {time_t      tv_sec;     /* seconds */suseconds_t tv_usec;    /* microseconds */};

gettimeofday系统调用是用内核vsyscall实现的。查看进程的maps, vsyscall在vdso(virtual dynamic shared object)区域。vdso区域是进程启动时内核向进程映射一段空间,这样做是为了减少某些频繁调用的系统调用的开销。

int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{const union mips_vdso_data *data = get_vdso_data();struct timespec ts;int ret;ret = do_realtime(&ts, data);if (ret)return ret;if (tv) {tv->tv_sec = ts.tv_sec;tv->tv_usec = ts.tv_nsec / 1000;}if (tz) {tz->tz_minuteswest = data->tz_minuteswest;tz->tz_dsttime = data->tz_dsttime;}return 0;
}
/* do realtime 直接读取导出的realtime时间*/
static __always_inline int do_realtime(struct timespec *ts,const union mips_vdso_data *data)
{u32 start_seq;u64 ns;do {start_seq = vdso_data_read_begin(data);if (data->clock_mode == VDSO_CLOCK_NONE)return -ENOSYS;ts->tv_sec = data->xtime_sec;ns = get_ns(data);} while (vdso_data_read_retry(data, start_seq));ts->tv_nsec = 0;timespec_add_ns(ts, ns);return 0;
}

下面是vdso导出的数据区域

union mips_vdso_data {struct {/*timekeeper 维护的realtime时间*/u64 xtime_sec;  u64 xtime_nsec;/*从realtime时间向monotonic时间的偏移*/u32 wall_to_mono_sec;u32 wall_to_mono_nsec;u32 seq_count;u32 cs_shift;u8 clock_mode;u32 cs_mult;u64 cs_cycle_last;u64 cs_mask;s32 tz_minuteswest;s32 tz_dsttime;};u8 page[PAGE_SIZE];
};

clock_gettime

#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);struct timespec {time_t   tv_sec;        /* seconds */long     tv_nsec;       /* nanoseconds */};

clockid 用来指定选择哪一个clock。
内核维护两个clock

  • CLOCK_REALTIME(wall clock): 墙上时间,记录从1970-01-01 00:00:00时刻开始的时间,当进行时间同步操作的时候会被修改。当没有进行时间同步时,跟CLOCK_MONOTONIC相同
  • CLOCK_MONOTONIC: 单调递增的时间,不受修改系统时间的影响。
int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
{const union mips_vdso_data *data = get_vdso_data();int ret;switch (clkid) {case CLOCK_REALTIME_COARSE:ret = do_realtime_coarse(ts, data);break;case CLOCK_MONOTONIC_COARSE:ret = do_monotonic_coarse(ts, data);break;case CLOCK_REALTIME:ret = do_realtime(ts, data);break;case CLOCK_MONOTONIC:ret = do_monotonic(ts, data);break;default:ret = -ENOSYS;break;}/* If we return -ENOSYS libc should fall back to a syscall. */return ret;
}

从代码中可以看出,当id是CLOCK_REALTIME时,进行的动作与gettimeofday相同。当id是CLOCK_MONOTONIC时,执行do_monotonic。

static __always_inline int do_monotonic(struct timespec *ts,const union mips_vdso_data *data)
{u32 start_seq;u64 ns;u32 to_mono_sec;u32 to_mono_nsec;do {start_seq = vdso_data_read_begin(data);if (data->clock_mode == VDSO_CLOCK_NONE)return -ENOSYS;ts->tv_sec = data->xtime_sec;ns = get_ns(data);to_mono_sec = data->wall_to_mono_sec;to_mono_nsec = data->wall_to_mono_nsec;} while (vdso_data_read_retry(data, start_seq));ts->tv_sec += to_mono_sec;ts->tv_nsec = 0;timespec_add_ns(ts, ns + to_mono_nsec);return 0;
}

do_monotonic同样是直接获取系统维护的时间xtime_sec, 但是后面要用wall_to_mono_*进行修正。
下面的例子来说明两个的区别:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>const char *command = "date -s \"2018-10-24 09:00:00\"";
int main(int argc, char *argv[])
{struct timeval time_now;struct timespec time_test;struct timeval time_change;char buffer[64] = {0};gettimeofday(&time_now, NULL);strftime(buffer, 64, "Current date/time(1): %m-%d-%Y/%T", localtime(&time_now.tv_sec));printf("%s\n", buffer);printf("realtime:\n");clock_gettime(CLOCK_REALTIME, &time_test);time_change.tv_sec = time_test.tv_sec;time_change.tv_usec = time_test.tv_nsec / 1000;strftime(buffer, 64, "Current date/time(2): %m-%d-%Y/%T", localtime(&time_change.tv_sec));printf("%s\n", buffer);printf("monotonic time:\n");clock_gettime(CLOCK_MONOTONIC, &time_test);time_change.tv_sec = time_test.tv_sec;time_change.tv_usec = time_test.tv_nsec / 1000;strftime(buffer, 64, "Current date/time(3): %m-%d-%Y/%T", localtime(&time_change.tv_sec));printf("%s\n", buffer);system(command);printf("\ndate change time %s:\n\n", command);printf("time now:\n");gettimeofday(&time_now, NULL);strftime(buffer, 64, "Current date/time(1): %m-%d-%Y/%T", localtime(&time_now.tv_sec));printf("%s\n", buffer);printf("realtime:\n");clock_gettime(CLOCK_REALTIME, &time_test);time_change.tv_sec = time_test.tv_sec;time_change.tv_usec = time_test.tv_nsec / 1000;strftime(buffer, 64, "Current date/time(2): %m-%d-%Y/%T", localtime(&time_change.tv_sec));printf("%s\n", buffer);printf("monotonic time:\n");clock_gettime(CLOCK_MONOTONIC, &time_test);time_change.tv_sec = time_test.tv_sec;time_change.tv_usec = time_test.tv_nsec / 1000;strftime(buffer, 64, "Current date/time(3): %m-%d-%Y/%T", localtime(&time_change.tv_sec));printf("%s\n", buffer);return 0;
}

下边是系统刚启动一小段时间的运行结果:

/mnt # ./date_test
Current date/time(1): 01-01-1970/00:46:51
realtime:
Current date/time(2): 01-01-1970/00:46:51
monotonic time:
Current date/time(3): 01-01-1970/00:46:51
Wed Oct 24 09:00:00 UTC 2018date change time date -s "2018-10-24 09:00:00":time now:
Current date/time(1): 10-24-2018/09:00:00
realtime:
Current date/time(2): 10-24-2018/09:00:00
monotonic time:
Current date/time(3): 01-01-1970/00:46:51

修改系统时间之后,用monotonic time 转化出来的localtime依然是从启动开始的实际间隔。

linux 时间系统 一 时间相关的系统调用相关推荐

  1. 计划任务linux时间,系统运维|在 Linux 中怎么使用 cron 计划任务

    没有时间运行命令?使用 cron 的计划任务意味着你不用熬夜程序也可以运行. 系统管理员(在许多好处中)的挑战之一是在你该睡觉的时候去运行一些任务.例如,一些任务(包括定期循环运行的任务)需要在没有人 ...

  2. Linux内核之时间系统

    Linux内核之时间系统 1.Linux时间系统 (1)CMOS时钟 (2)系统时钟 (3)节拍数(jiffies) (4)墙上时间(xtime) 2.重要数据结构 (1)struct tk_read ...

  3. linux 时间与定时器编程原理,浅析 Linux 中的时间编程和实现原理-嵌入式-火龙果软件工程...

    引子 我们都生活在时间中,但却无法去思考它.什么是时间呢?似乎这是一个永远也不能被回答的问题.然而作为一个程序员,在工作中,总有那么几次我必须思考什么是时间.比如,需要知道一段代码运行了多久:要在 l ...

  4. Linux调度系统全景指南(中篇)

    点击上方蓝字关注公众号,更多经典内容等着你 | 导语本文主要是讲Linux的调度系统, 由于全部内容太多,分三部分来讲,本篇是中篇(主要讲抢占和时钟),上篇请看(CPU和中断):Linux调度系统全景 ...

  5. linux系统设置系统时间的方法

    Linux系统设置系统时间有两种方法: 1.使用命令date 2.使用系统调用settimeofday,gettimeofday 注意:不管使用上面哪一种方法都必须是root权限. 如果系统连接上了网 ...

  6. linux内核时间函数us,Linux上系统时间函数、DST等相关有关问题总结

    http://www.reader8.cn/jiaocheng/20120910/1995886.html 2012 Linux下系统时间函数.DST等相关问题总结1. 内核中时间的基本类型:在Lin ...

  7. linux 系统时间 硬件时间,linux 设置系统时间和硬件时间

    linux 的系统时间有时跟硬件时间是不同步的 Linux时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟.系统时钟是指当前Linux Kernel ...

  8. linux时间调整为dst,Linux上系统时间函数、DST等相关有关问题总结

    Linux下系统时间函数.DST等相关问题总结 1. 内核中时间的基本类型: 在Linux内核中,常见的时间类型有以下两种:系统时间(system time)和实时时间(real time),其实,方 ...

  9. linux获得系统时间 c,linux c 获取系统时间

    #include main() { time_t timep; time (&timep); printf("%s",asctime(gmtime(&timep)) ...

最新文章

  1. Spring框架的灵魂IOC和AOP
  2. 选择海外数据中心是否等级越高越好
  3. ML之Clustering之LPA:LPA算法主要思路、输出结果、代码实现等相关配图之详细攻略
  4. 跨链Cosmos(6)ABCI 原理
  5. Xamarin 中Visual Studio创建项目提示错误
  6. AWS发布低延迟互动直播服务
  7. leetcode 5756. 两个数组最小的异或值之和(状态压缩dp)
  8. UVALive 6511 Term Project
  9. java 父子级json组装不用递归_2020面试阿里Java研发岗题库总结,想虐面试官不能错过的面试宝典...
  10. Mr.J--树、二叉树、森林的转换
  11. OpenCV系列(一)之图像平滑
  12. 计算机网络 第五章 运输层
  13. 23.使用非阻塞IO 2
  14. 易考防作弊功能有哪些_浙江考试院发公告,上百名考生考研违规,你可以不努力但不能作弊...
  15. 播放抓取的H263 RTP视频
  16. 学习java软件开发大概要多久?
  17. 如何学习数字集成电路:数字IC必读书籍
  18. python lncrna_使用CNCI分析lncRNA
  19. Altium Designer 19简易教程(原理图的绘制)
  20. 微信小程序上传文件功能实现

热门文章

  1. 脚手架工程发布与使用
  2. 信捷XDPLC十轴(包含)及以下万能通用程序模板,用进制数据和S状态完美结合
  3. 编程语言-11-编程八荣八耻及python中的荣耻观
  4. 富文本框显示OLE对象
  5. 计算机win7基础知识题库,WIN7操作系统练习题题库版
  6. WinForm中关于CausesValidation与Validating事件引发的一些发现.
  7. 手机safari导入html书签,iPhone手机Safari浏览器书签如何同步至电脑?
  8. Unity 法线贴图、高光贴图、Cube Map shader
  9. 2021年安全员-A证(江苏省)考试题及安全员-A证(江苏省)考试报名
  10. 2021年中国焊接钢管行业产业链及发展现状分析,产销大幅回升,下游建筑行业应用占比超70%「图」