include/common/time.h
Time calculation functions and macros.
- Copyright (C) 2000-2007 Willy Tarreau - w@1wt.eu
+ Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
#define MINTIME(old, new) (((new)<0)?(old):(((old)<0||(new)<(old))?(new):(old)))
#define SETNOW(a) (*a=now)
-extern struct timeval now; /* the current date at any moment */
+extern struct timeval now; /* internal date is a monotonic function of real clock */
+extern struct timeval date; /* the real current date */
extern struct timeval start_date; /* the process's start date */
return tv;
}
+/* tv_now_mono: sets <date> to the current time (wall clock), <mono> to a value
+ * following a monotonic function, and applies any required correction if the
+ * time goes backwards. Note that while we could improve it a bit by checking
+ * that the new date is not too far in the future, it is not much necessary to
+ * do so.
+ */
+REGPRM2 struct timeval *tv_now_mono(struct timeval *mono, struct timeval *wall);
+
/*
* sets a struct timeval to its highest value so that it can never happen
* note that only tv_usec is necessary to detect it since a tv_usec > 999999
* is normally not possible.
- *
*/
-
REGPRM1 static inline struct timeval *tv_eternity(struct timeval *tv)
{
tv->tv_sec = tv->tv_usec = TV_ETERNITY;
struct http_txn txn; /* current HTTP transaction being processed. Should become a list. */
struct {
int logwait; /* log fields waiting to be collected : LW_* */
- struct timeval tv_accept; /* date of the accept() (beginning of the session) */
+ struct timeval accept_date; /* date of the accept() in user date */
+ struct timeval tv_accept; /* date of the accept() in internal date (monotonic) */
struct timeval tv_request; /* date the request arrives, {0,0} if never occurs */
long t_queue; /* delay before the session gets out of the connect queue, -1 if never occurs */
long t_connect; /* delay before the connect() to the server succeeds, -1 if never occurs */
*/
/* will be needed further to delay some tasks */
- tv_now(&now);
+ tv_now_mono(&now, &date);
if ((curproxy = proxy) == NULL) {
Alert("parsing %s : no <listen> line. Nothing to do !\n",
if (s->proxy->options & PR_O_SSL3_CHK) {
/* SSL requires that we put Unix time in the request */
- int gmt_time = htonl(now.tv_sec);
+ int gmt_time = htonl(date.tv_sec);
memcpy(s->proxy->check_req + 11, &gmt_time, 4);
}
/*
* Client-side variables and functions.
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
else
s->logs.logwait = p->to_log;
- s->logs.tv_accept = now;
+ s->logs.accept_date = date; /* user-visible date for logging */
+ s->logs.tv_accept = now; /* corrected date for internal use */
tv_zero(&s->logs.tv_request);
s->logs.t_queue = -1;
s->logs.t_connect = -1;
/*
* FD polling functions for linux epoll()
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
fd = MIN(maxfd, global.tune.maxpollevents);
status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
- tv_now(&now);
+ tv_now_mono(&now, &date);
for (count = 0; count < status; count++) {
fd = epoll_events[count].data.fd;
/*
* FD polling functions for FreeBSD kqueue()
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
kev, // struct kevent *eventlist
fd, // int nevents
to_ptr); // const struct timespec *timeout
- tv_now(&now);
+ tv_now_mono(&now, &date);
for (count = 0; count < status; count++) {
fd = kev[count].ident;
/*
* FD polling functions for generic poll()
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
wait_time = __tv_ms_elapsed(&now, exp) + 1;
status = poll(poll_events, nbfd, wait_time);
- tv_now(&now);
+ tv_now_mono(&now, &date);
for (count = 0; status > 0 && count < nbfd; count++) {
fd = poll_events[count].fd;
/*
* FD polling functions for generic select()
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
NULL,
tv_isset(exp) ? &delta : NULL);
- tv_now(&now);
+ tv_now_mono(&now, &date);
if (status <= 0)
return;
* returning now without checking epoll_wait().
*/
if (++last_skipped <= 1) {
- tv_now(&now);
+ tv_now_mono(&now, &date);
return;
}
}
spec_processed = 0;
status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
- tv_now(&now);
+ tv_now_mono(&now, &date);
for (count = 0; count < status; count++) {
int e = epoll_events[count].events;
global.rlimit_memmax = HAPROXY_MEMMAX;
#endif
- tv_now(&now);
+ tv_now_mono(&now, &date);
start_date = now;
init_task();
{
struct timeval next;
- tv_now(&now);
+ tv_now_mono(&now, &date);
while (1) {
process_runnable_tasks(&next);
/*
* General logging functions.
*
- * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
va_start(argp, fmt);
- get_localtime(now.tv_sec, &tm);
+ get_localtime(date.tv_sec, &tm);
fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
vfprintf(stderr, fmt, argp);
if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
va_start(argp, fmt);
- get_localtime(now.tv_sec, &tm);
+ get_localtime(date.tv_sec, &tm);
fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
vfprintf(stderr, fmt, argp);
if (level < 0 || progname == NULL || message == NULL)
return;
- if (now.tv_sec != tvsec || dataptr == NULL) {
+ if (unlikely(date.tv_sec != tvsec || dataptr == NULL)) {
/* this string is rebuild only once a second */
struct tm tm;
- tvsec = now.tv_sec;
+ tvsec = date.tv_sec;
get_localtime(tvsec, &tm);
hdr_len = snprintf(logmsg, sizeof(logmsg),
(const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
pn, sizeof(pn));
- get_localtime(s->logs.tv_accept.tv_sec, &tm);
+ get_localtime(s->logs.accept_date.tv_sec, &tm);
/* FIXME: let's limit ourselves to frontend logging for now. */
tolog = fe->to_log;
ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
- tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.tv_accept.tv_usec/1000,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
fe->id, be->id, svid,
t_request,
(s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
/*
* Proxy variables and functions.
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
stopping = 1;
p = proxy;
- tv_now(&now); /* else, the old time before select will be used */
+ tv_now_mono(&now, &date); /* else, the old time before select will be used */
while (p) {
if (p->state != PR_STSTOPPED) {
Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
err = 0;
p = proxy;
- tv_now(&now); /* else, the old time before select will be used */
+ tv_now_mono(&now, &date); /* else, the old time before select will be used */
while (p) {
if (p->state != PR_STERROR &&
p->state != PR_STSTOPPED &&
struct listener *l;
p = proxy;
- tv_now(&now); /* else, the old time before select will be used */
+ tv_now_mono(&now, &date); /* else, the old time before select will be used */
while (p) {
if (p->state == PR_STPAUSED) {
Warning("Enabling proxy %s.\n", p->id);
/*
* Time calculation functions.
*
- * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include <common/standard.h>
#include <common/time.h>
-struct timeval now; /* the current date at any moment */
+struct timeval now; /* internal date is a monotonic function of real clock */
+struct timeval date; /* the real current date */
struct timeval start_date; /* the process's start date */
/*
return __tv_isgt(tv1, tv2);
}
+/* tv_now_mono: sets <date> to the current time (wall clock), <mono> to a value
+ * following a monotonic function, and applies any required correction if the
+ * time goes backwards. Note that while we could improve it a bit by checking
+ * that the new date is not too far in the future, it is not much necessary to
+ * do so.
+ */
+REGPRM2 struct timeval *tv_now_mono(struct timeval *mono, struct timeval *wall)
+{
+ static struct timeval tv_offset;
+ struct timeval adjusted;
+
+ gettimeofday(wall, NULL);
+ __tv_add(&adjusted, wall, &tv_offset);
+ if (unlikely(__tv_islt(&adjusted, mono))) {
+ __tv_remain(wall, mono, &tv_offset);
+ return mono;
+ }
+ *mono = adjusted;
+ return mono;
+}
+
char *human_time(int t, short hz_div) {
static char rv[sizeof("24855d23h")+1]; // longest of "23h59m" and "59m59s"
char *p = rv;