Use timevals everywhere where it is possible, including API between main

loop and event dispatchers. This simplifies code and eliminates a bug,
when kevent dispatcher is called with 0 timeout.

While here, in the main loop call gettimeofday() right after event
dispatcher returns. Otherwise, we are using outdated "timeofday" in
second part of the loop. I don't know any bugs because of that, but
they are possible.
This commit is contained in:
Gleb Smirnoff 2019-05-08 14:19:46 -07:00
parent cad8c922f0
commit 1d363c209f
4 changed files with 31 additions and 47 deletions

View File

@ -42,7 +42,7 @@ typedef int event_module_add_t(struct event *);
typedef int event_module_del_t(struct event *, int flags); typedef int event_module_del_t(struct event *, int flags);
typedef int event_module_init_t(void); typedef int event_module_init_t(void);
typedef void event_module_fini_t(void); typedef void event_module_fini_t(void);
typedef int event_module_process_t(u_long); typedef int event_module_process_t(struct timeval *);
struct event_module { struct event_module {
event_module_add_t *add; event_module_add_t *add;
event_module_del_t *del; event_module_del_t *del;

View File

@ -178,27 +178,21 @@ kqueue_set(struct event *ev, short filter, u_short flags, u_int fflags)
} }
static int static int
kqueue_process(u_long timer) kqueue_process(struct timeval *tv)
{ {
struct event *ev; struct event *ev;
int events, n, i; int events, n, i;
struct timespec ts, *tp; struct timespec ts;
n = (int) nchanges; n = (int) nchanges;
nchanges = 0; nchanges = 0;
if (timer == 0) { TIMEVAL_TO_TIMESPEC(tv, &ts);
tp = NULL;
} else {
ts.tv_sec = timer / 1000;
ts.tv_nsec = (timer % 1000) * 1000000;
tp = &ts;
}
DPRINTF(E_DEBUG, L_GENERAL, "kevent timer: %lu, changes: %d\n", DPRINTF(E_DEBUG, L_GENERAL, "kevent timer: %lu.%06lu, changes: %d\n",
timer, n); ts.tv_sec, ts.tv_nsec, n);
events = kevent(kq, change_list, n, event_list, MAXEVENTS, tp); events = kevent(kq, change_list, n, event_list, MAXEVENTS, &ts);
if (events == -1) { if (events == -1) {
if (errno == EINTR) if (errno == EINTR)
@ -208,12 +202,6 @@ kqueue_process(u_long timer)
DPRINTF(E_DEBUG, L_GENERAL, "kevent events: %d\n", events); DPRINTF(E_DEBUG, L_GENERAL, "kevent events: %d\n", events);
if (events == 0) {
if (timer != 0)
return (0);
DPRINTF(E_FATAL, L_GENERAL, "kevent() returned no events. EXITING\n");
}
for (i = 0; i < events; i++) { for (i = 0; i < events; i++) {
if (event_list[i].flags & EV_ERROR) { if (event_list[i].flags & EV_ERROR) {
DPRINTF(E_ERROR, L_GENERAL, DPRINTF(E_ERROR, L_GENERAL,

View File

@ -1112,7 +1112,6 @@ main(int argc, char **argv)
struct upnphttp * next; struct upnphttp * next;
struct timeval tv, timeofday, lastnotifytime = {0, 0}; struct timeval tv, timeofday, lastnotifytime = {0, 0};
time_t lastupdatetime = 0, lastdbtime = 0; time_t lastupdatetime = 0, lastdbtime = 0;
u_long timeout; /* in milliseconds */
int last_changecnt = 0; int last_changecnt = 0;
pid_t scanner_pid = 0; pid_t scanner_pid = 0;
struct event ssdpev, httpev, monev; struct event ssdpev, httpev, monev;
@ -1184,6 +1183,9 @@ main(int argc, char **argv)
httpev = (struct event ){ .fd = shttpl, .rdwr = EVENT_READ, .process = ProcessListen }; httpev = (struct event ){ .fd = shttpl, .rdwr = EVENT_READ, .process = ProcessListen };
event_module.add(&httpev); event_module.add(&httpev);
if (gettimeofday(&timeofday, 0) < 0)
DPRINTF(E_FATAL, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
#ifdef TIVO_SUPPORT #ifdef TIVO_SUPPORT
if (GETFLAG(TIVO_MASK)) if (GETFLAG(TIVO_MASK))
{ {
@ -1208,18 +1210,17 @@ main(int argc, char **argv)
tivo_bcast.sin_family = AF_INET; tivo_bcast.sin_family = AF_INET;
tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress());
tivo_bcast.sin_port = htons(2190); tivo_bcast.sin_port = htons(2190);
lastbeacontime = timeofday;
} }
} }
#endif #endif
reload_ifaces(0); reload_ifaces(0); /* sends SSDP notifies */
lastnotifytime.tv_sec = time(NULL) + runtime_vars.notify_interval; lastnotifytime = timeofday;
/* main loop */ /* main loop */
while (!quitting) while (!quitting)
{ {
if (gettimeofday(&timeofday, 0) < 0)
DPRINTF(E_FATAL, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
/* Check if we need to send SSDP NOTIFY messages and do it if /* Check if we need to send SSDP NOTIFY messages and do it if
* needed */ * needed */
tv = lastnotifytime; tv = lastnotifytime;
@ -1233,41 +1234,38 @@ main(int argc, char **argv)
runtime_vars.port, runtime_vars.notify_interval); runtime_vars.port, runtime_vars.notify_interval);
} }
lastnotifytime = timeofday; lastnotifytime = timeofday;
timeout = runtime_vars.notify_interval * 1000; tv.tv_sec = runtime_vars.notify_interval;
tv.tv_usec = 0;
} }
else else
{ {
timevalsub(&tv, &timeofday); timevalsub(&tv, &timeofday);
timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
} }
#ifdef TIVO_SUPPORT #ifdef TIVO_SUPPORT
if (sbeacon >= 0) if (sbeacon >= 0)
{ {
u_long beacontimeout; struct timeval beacontv;
tv = lastbeacontime; beacontv = lastbeacontime;
tv.tv_sec += beacon_interval; beacontv.tv_sec += beacon_interval;
if (timevalcmp(&timeofday, &tv, >=)) if (timevalcmp(&timeofday, &beacontv, >=))
{ {
sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1);
lastbeacontime = timeofday; lastbeacontime = timeofday;
beacontimeout = beacon_interval * 1000;
if (timeout > beacon_interval * 1000)
timeout = beacon_interval * 1000;
/* Beacons should be sent every 5 seconds or /* Beacons should be sent every 5 seconds or
* so for the first minute, then every minute * so for the first minute, then every minute
* or so thereafter. */ * or so thereafter. */
if (beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60) if (beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60)
beacon_interval = 60; beacon_interval = 60;
beacontv.tv_sec = beacon_interval;
beacontv.tv_usec = 0;
} }
else else
{ {
timevalsub(&tv, &timeofday); timevalsub(&beacontv, &timeofday);
beacontimeout = tv.tv_sec * 1000 +
tv.tv_usec / 1000;
} }
if (timeout > beacontimeout) if (timevalcmp(&tv, &beacontv, >))
timeout = beacontimeout; tv = beacontv;
} }
#endif #endif
@ -1282,13 +1280,16 @@ main(int argc, char **argv)
#endif #endif
} else } else
/* Keep checking for the scanner every sec. */ /* Keep checking for the scanner every sec. */
timeout = 1000; tv.tv_sec = 1;
} }
event_module.process(timeout); event_module.process(&tv);
if (quitting) if (quitting)
goto shutdown; goto shutdown;
if (gettimeofday(&timeofday, 0) < 0)
DPRINTF(E_FATAL, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
upnpevents_gc(); upnpevents_gc();
/* increment SystemUpdateID if the content database has changed, /* increment SystemUpdateID if the content database has changed,

View File

@ -142,9 +142,8 @@ select_del(struct event *ev, int flags)
} }
static int static int
select_process(u_long msec) select_process(struct timeval *tv)
{ {
struct timeval tv, *tp;
struct event *ev; struct event *ev;
int ready, i; int ready, i;
@ -155,14 +154,10 @@ select_process(u_long msec)
max_fd = events[i]->fd; max_fd = events[i]->fd;
} }
tv.tv_sec = (long) (msec / 1000);
tv.tv_usec = (long) ((msec % 1000) * 1000);
tp = &tv;
work_read_fd_set = master_read_fd_set; work_read_fd_set = master_read_fd_set;
work_write_fd_set = master_write_fd_set; work_write_fd_set = master_write_fd_set;
ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp); ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tv);
if (ready == -1) { if (ready == -1) {
if (errno == EINTR) if (errno == EINTR)