声明
在 src\core\ngx_times.c 中:
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec);
实现
在 src\core\ngx_times.c 中:
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec) { #if (NGX_HAVE_CLOCK_MONOTONIC)struct timespec ts;#if defined(CLOCK_MONOTONIC_FAST)clock_gettime(CLOCK_MONOTONIC_FAST, &ts); #elseclock_gettime(CLOCK_MONOTONIC, &ts); #endifsec = ts.tv_sec;msec = ts.tv_nsec / 1000000;#endifreturn (ngx_msec_t) sec * 1000 + msec; }
通过 gcc -E 处理 预处理指令后
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec) {struct timespec ts;clock_gettime( # 204 "src/core/ngx_times.c" 3 41 # 204 "src/core/ngx_times.c", &ts);sec = ts.tv_sec;msec = ts.tv_nsec / 1000000;return (ngx_msec_t) sec * 1000 + msec; }
NGX_HAVE_CLOCK_MONOTONIC 宏
objs/ngx_auto_config.h:287:#define NGX_HAVE_CLOCK_MONOTONIC 1
在 objs/ngx_auto_config.h 中
#ifndef NGX_HAVE_CLOCK_MONOTONIC #define NGX_HAVE_CLOCK_MONOTONIC 1 #endif
NGX_HAVE_CLOCK_MONOTONIC
是一个宏定义,用于指示系统是否支持
clock_gettime()
函数的CLOCK_MONOTONIC
时钟源
CLOCK_MONOTONIC
是 POSIX 标准中定义的一种时钟类型,表示单调递增的时间。与
CLOCK_REALTIME
不同,CLOCK_MONOTONIC
的时间不会因为系统时间的调整(例如用户手动修改系统时间或通过 NTP 同步)而发生跳变。因此,它非常适合用于测量时间间隔或计算超时
NGX_HAVE_CLOCK_MONOTONIC
宏的作用是检查当前系统是否支持CLOCK_MONOTONIC
如果支持,Nginx 会使用
clock_gettime(CLOCK_MONOTONIC, ...)
来获取高精度的时间戳,从而实现更精确的时间管理在 Nginx 的构建过程中,通常会通过
configure
脚本来检测系统是否支持CLOCK_MONOTONIC
编译时,
configure
脚本会尝试编译一段测试代码,调用clock_gettime()
并传入CLOCK_MONOTONIC
参数。如果编译成功且运行正常,则说明系统支持
CLOCK_MONOTONIC
,此时会在生成的配置头文件(如objs/ngx_auto_config.h
)中定义NGX_HAVE_CLOCK_MONOTONIC
宏。如果编译失败或运行异常,则不会定义该宏
CLOCK_MONOTONIC_FAST 宏
未定义
CLOCK_MONOTONIC_FAST
用于替代标准的CLOCK_MONOTONIC
,在保证时间单调递增的前提下,减少时间获取的系统调用开销
- 在 FreeBSD 等类 Unix 系统中,
CLOCK_MONOTONIC_FAST
是系统原生支持的时钟类型(通过clock_gettime()
使用)。- 在 Linux 等不支持该时钟的系统上,Nginx 会通过宏定义将其回退到
CLOCK_MONOTONIC
,确保兼容性。
CLOCK_MONOTONIC
表示一种单调递增的时间源,从系统启动(即内核初始化完成)开始计时
- 不受系统时间调整的影响 :即使管理员手动修改了系统时间(例如通过
date
命令或 NTP 服务),CLOCK_MONOTONIC
的值也不会受到影响。- 单调递增 :该时钟只会随着时间向前推进,不会回退(除非系统重启)。
- 高分辨率 :通常提供纳秒级别的精度。
所以
clock_gettime(CLOCK_MONOTONIC, &ts);
成立
综上,在我的 Ubuntu 环境下运行的实际代码应该是:
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec) {struct timespec ts;clock_gettime(CLOCK_MONOTONIC, &ts);sec = ts.tv_sec;msec = ts.tv_nsec / 1000000;return (ngx_msec_t) sec * 1000 + msec; }
函数的目标是获取一个基于单调时间(monotonic time)的时间戳,以毫秒为单位返回。单调时间的特点是不会受到系统时间调整的影响,适合用于计时和超时检测等场景
定义一个
timespec
结构体变量ts
,用于存储通过clock_gettime
获取的时间信息
struct timespec
是 POSIX 标准中定义的时间结构体,包含两个字段:
tv_sec
:秒数部分。tv_nsec
:纳秒部分(1 秒 = 10^9 纳秒)。调用
clock_gettime
函数,获取当前的单调时间,并将结果存储到ts
中
CLOCK_MONOTONIC
是一种单调递增的时钟源,不会受到系统时间调整(如手动修改系统时间或 NTP 同步)的影响。
clock_gettime
是 POSIX 标准中的函数,用于获取高精度时间将
ts.tv_sec
(单调时间的秒数部分)赋值给函数参数sec
将
ts.tv_nsec
(纳秒部分)转换为毫秒,并赋值给函数参数msec
将秒数转换为毫秒,并加上毫秒部分,最终返回一个以毫秒为单位的时间戳
clock_gettime
函数
clock_gettime
是 POSIX 标准中定义的一个函数,用于获取高精度的时间信息。它能够从指定的时钟源(clock source)中读取当前时间,并以纳秒级精度返回结果。函数原型
#include <time.h>int clock_gettime(clockid_t clk_id, struct timespec *tp);
clk_id
:指定时钟源(clock source),决定了时间的来源。
常见的时钟源包括:
CLOCK_REALTIME
:系统实时时间(wall-clock time),可以被手动调整或通过 NTP 同步。
CLOCK_MONOTONIC
:单调递增的时间,从某个固定点开始计时,不受系统时间调整的影响。
CLOCK_PROCESS_CPUTIME_ID
:进程的 CPU 时间。
CLOCK_THREAD_CPUTIME_ID
:线程的 CPU 时间。
CLOCK_BOOTTIME
(Linux 特有):类似于CLOCK_MONOTONIC
,但包括系统休眠时间。选择不同的时钟源会影响时间的用途。
tp
:指向一个
struct timespec
结构体的指针,用于存储获取到的时间信息。返回值
- 成功时返回
0
。- 失败时返回
-1
,并设置errno
表示错误原因。