Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#1308 closed defect (duplicate)

nginx timer don't work if change system date.

Reported by: panjiearray@… Owned by:
Priority: critical Milestone:
Component: nginx-core Version: 1.12.x
Keywords: timer Cc:
uname -a: Linux AN 3.10.0-327.28.2.5.el7.x86_64 #1 SMP Tue May 9 23:37:12 EDT 2017 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.12.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)
configure arguments: --prefix=/ca/ --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx.lock --conf-path=/ca/conf/nginx.conf --error-log-path=/var/crash/nginx-error.log --http-log-path=/var/crash/nginx-access.log --with-cc-opt='-w -I../../../include -I../../../lib/libuinet-atcp/lib/libuinet/machine_include -I../../../lib/libuinet-atcp/lib/libuinet/api_include -I../../../lib -I../../../../src -I../../../lib/libuinet-atcp/lib/libuinet_sysctl'

Description

I register a timer used by function ngx_add_timer(), and it works well. When time expire, event handler will execute.
But if I change system date, for example, today is 2017/7/4, I change system date to 2017/7/3, then nginx timer can not work well, and no longer trigger event handler.

Is it a bug? or I don't understood how to use ngx_add_timer?

Please help, thankyou.

Change History (4)

comment:1 by panjiearray@…, 3 years ago

I think ngx_gettimeofday() in function ngx_time_update() caused this issue.

#define ngx_gettimeofday(tp) (void) gettimeofday(tp, NULL);

because gettimeofday() gives the number of seconds and microseconds since the Epoch, and if change system time, then the return value of gettimeofday() will change to previous or later time immediately, then caused nginx timer works abnormally.

comment:2 by panjiearray@…, 3 years ago

My idea have been verified.
I used uptime instead, then this issue disapper.

static void
ngx_get_uptime_sec(time_t *sec)
{

struct sysinfo s_info;
sysinfo(&s_info);
*sec = (time_t)s_info.uptime;
return;

}

void
ngx_time_update(void)
{

u_char *p0, *p1, *p2, *p3;
ngx_tm_t tm, gmt;
time_t sec;
ngx_uint_t msec;
ngx_time_t *tp;
struct timeval tv;

if (!ngx_trylock(&ngx_time_lock)) {

return;

}

ngx_gettimeofday(&tv);

sec = tv.tv_sec;
ngx_get_uptime_sec(&sec); <-- second used uptime instead of tv.tv_sec.
msec = tv.tv_usec / 1000;
......

}

comment:3 by Maxim Dounin, 3 years ago

Resolution: duplicate
Status: newclosed

The problem is that nginx uses system time to control expiration of timers, and when you create a timer which is expected to expire in 60 seconds, you are in fact creating a timer which will expire in <current time + 5 seconds>. Changing system time is not something known to nginx, and so timers added before the change will expire at the time they were set to expire when added.

There is a ticket #189 about improving things by using clock_gettime(CLOCK_MONOTONIC) where it is available.

comment:4 by panjiearray@…, 3 years ago

hi, whether monotonic_timers-3.patch​ or others at ticket #189 can work on FreeBSD, I tried monotonic_timers-3.patch​, it only works on Linux.
Please help to give me a suggestion.
Thank you very much.

Note: See TracTickets for help on using tickets.