From c0c7cdbdcc11767799b4f5a2b3c75ed2eca40dde Mon Sep 17 00:00:00 2001 From: Kevin Easton Date: Sun, 7 Jun 2015 00:03:09 +1000 Subject: [PATCH] Rework the calculation of the select timeout in io() to be based on absolute wake time An absolute wake time is now calculated and updated by set_server_bits(), TimerTimeout() and tclTimerTimeout(). This is then used to calculate the actual select() timeout, instead of having those functions calculate a relative timeout value themselves. This significantly simplifies those functions, since the underlying values tend to be recorded as absolute times. It also allows us to disentangle tclTimeTimeout from TimerTimeout(), and move the responsibility for calculating the QUEUE_SENDS wake time from TimerTimeout() to set_server_bits() where it belongs. The QUEUE_SENDS and CONNECT_DELAY wake up times will also now be correctly calculated, based on the last sent time and connect time respectively. --- include/server.h | 2 +- include/tcl_bx.h | 1 + include/timer.h | 7 +---- source/irc.c | 62 ++++++++++++++++++++++----------------------- source/server.c | 27 ++++++++++++++------ source/tcl_public.c | 44 ++++++++------------------------ source/timer.c | 23 +++-------------- 7 files changed, 67 insertions(+), 99 deletions(-) diff --git a/include/server.h b/include/server.h index 8c0d6fc..26b083c 100644 --- a/include/server.h +++ b/include/server.h @@ -227,7 +227,7 @@ extern SGroup *server_group_list; void BX_server_is_connected (int, int); int BX_parse_server_index (char *); void BX_parse_server_info (char *, char **, char **, char **, char **); - long set_server_bits (fd_set *, fd_set *); + void set_server_bits (fd_set *rd, fd_set *wr, struct timeval *wake_time); void BX_set_server_itsname (int, char *); void BX_set_server_version (int, int); char *BX_get_possible_umodes(int); diff --git a/include/tcl_bx.h b/include/tcl_bx.h index 8816694..3aa0e38 100644 --- a/include/tcl_bx.h +++ b/include/tcl_bx.h @@ -19,6 +19,7 @@ typedef struct { extern cmd_t C_msg[]; extern cmd_t C_dcc[]; +void tclTimerTimeout(struct timeval *wake_time); int check_tcl_dcc (char *, char *, char *, int); void tcl_command (char *, char *, char *, char *); diff --git a/include/timer.h b/include/timer.h index 1da8a49..30210d3 100644 --- a/include/timer.h +++ b/include/timer.h @@ -16,14 +16,9 @@ extern int kill_timer(char *); extern void BX_delete_all_timers (void); extern int timer_exists (char *ref); - -extern time_t TimerTimeout (void); +void TimerTimeout(struct timeval *wake_time); char *tcl_add_timer (TimerList **, long, char *, unsigned long); int tcl_remove_timer (TimerList **, unsigned long); int timer_callback_exists(void *); -time_t tclTimerTimeout(time_t); - -#define MAGIC_TIMEOUT 100000000 - #endif /* _TIMER_H_ */ diff --git a/source/irc.c b/source/irc.c index 11612e5..ad56794 100644 --- a/source/irc.c +++ b/source/irc.c @@ -1196,13 +1196,10 @@ extern void set_screens (fd_set *, fd_set *); void BX_io (const char *what) { static int level = 0; - long clock_timeout = 0, - timer_timeout = 0, - server_timeout = 0, - real_timeout = 0; - static struct timeval my_now, + long clock_timeout = 0; + struct timeval my_now, my_timer, - *time_ptr = &my_timer; + timeout; int hold_over, rc; fd_set rd, wd; static int old_level = 0; @@ -1211,9 +1208,6 @@ void BX_io (const char *what) level++; - get_time(&my_now); - now = my_now.tv_sec; - if (x_debug & DEBUG_WAITS) { if (level != old_level) @@ -1237,6 +1231,9 @@ void BX_io (const char *what) caller[level] = what; + get_time(&my_now); + now = my_now.tv_sec; + /* CHECK FOR CPU SAVER MODE */ if (!cpu_saver && get_int_var(CPU_SAVER_AFTER_VAR)) if (now - idle_time > get_int_var(CPU_SAVER_AFTER_VAR) * 60) @@ -1250,7 +1247,6 @@ void BX_io (const char *what) #ifndef GUI set_screens(&rd, &wd); #endif - server_timeout = set_server_bits(&rd, &wd); set_process_bits(&rd); set_socket_read(&rd, &wd); set_nslookupfd(&rd); @@ -1258,38 +1254,40 @@ void BX_io (const char *what) gui_setfd(&rd); #endif - clock_timeout = (60 - (my_now.tv_sec % 60)) * 1000; + clock_timeout = 60 - (my_now.tv_sec % 60); if (cpu_saver && get_int_var(CPU_SAVER_EVERY_VAR)) - clock_timeout += (get_int_var(CPU_SAVER_EVERY_VAR) - 1) * 60000; + clock_timeout += (get_int_var(CPU_SAVER_EVERY_VAR) - 1) * 60; - timer_timeout = TimerTimeout(); + my_timer.tv_sec = my_now.tv_sec + clock_timeout; + my_timer.tv_usec = 0; - if ((hold_over = unhold_windows())) - real_timeout = 0; - else if (timer_timeout <= clock_timeout) - real_timeout = timer_timeout; - else - real_timeout = clock_timeout; + set_server_bits(&rd, &wd, &my_timer); - if (server_timeout >= 0 && server_timeout < real_timeout) - real_timeout = server_timeout; + tclTimerTimeout(&my_timer); - time_ptr = &my_timer; + TimerTimeout(&my_timer); - if (real_timeout == -1) - time_ptr = NULL; + if ((hold_over = unhold_windows()) || time_cmp(&my_timer, &my_now) < 0) + { + timeout.tv_sec = 0; + timeout.tv_usec = 0; + } else { - time_ptr->tv_sec = real_timeout / 1000; - time_ptr->tv_usec = ((real_timeout % 1000) * 1000); + timeout.tv_sec = my_timer.tv_sec - my_now.tv_sec; + timeout.tv_usec = my_timer.tv_usec - my_now.tv_usec; + if (timeout.tv_usec < 0) + { + timeout.tv_sec--; + timeout.tv_usec += 1000000; + } } /* GO AHEAD AND WAIT FOR SOME DATA TO COME IN */ - switch ((rc = new_select(&rd, &wd, time_ptr))) + switch ((rc = new_select(&rd, &wd, &timeout))) { case 0: - if (server_timeout >= 0) - do_idle_server(); + do_idle_server(); break; case -1: { @@ -1309,7 +1307,8 @@ void BX_io (const char *what) default: { cntl_c_hit = 0; - now = time(NULL); + get_time(&my_now); + now = my_now.tv_sec; make_window_current(NULL); do_server(&rd, &wd); do_processes(&rd); @@ -1327,7 +1326,8 @@ void BX_io (const char *what) } } - now = time(NULL); + get_time(&my_now); + now = my_now.tv_sec; ExecuteTimers(); #ifdef WANT_TCL check_utimers(); diff --git a/source/server.c b/source/server.c index 717c92f..46246c5 100644 --- a/source/server.c +++ b/source/server.c @@ -227,19 +227,19 @@ void close_unattached_servers(void) * set_server_bits: Sets the proper bits in the fd_set structure according to * which servers in the server list have currently active read descriptors. */ -long set_server_bits (fd_set *rd, fd_set *wr) +void set_server_bits (fd_set *rd, fd_set *wr, struct timeval *wake_time) { int i; - long timeout = -1; for (i = 0; i < number_of_servers; i++) { if (server_list[i].reconnect > 0) { - /* CONNECT_DELAY is in seconds but we must - * return in milliseconds. - */ - timeout = get_int_var(CONNECT_DELAY_VAR)*1000; + struct timeval connect_wake_time = server_list[i].connect_time; + connect_wake_time.tv_sec += get_int_var(CONNECT_DELAY_VAR); + + if (time_cmp(wake_time, &connect_wake_time) > 0) + *wake_time = connect_wake_time; } if (server_list[i].read > -1) @@ -250,9 +250,20 @@ long set_server_bits (fd_set *rd, fd_set *wr) FD_SET(server_list[i].write, wr); #endif } - return timeout; -} + /* Check for a QUEUE_SENDS wake_time */ + if (serverqueue) + { + struct timeval queue_wake_time; + + queue_wake_time.tv_sec = server_list[serverqueue->server].last_sent + + get_int_var(QUEUE_SENDS_VAR); + queue_wake_time.tv_usec = 0; + + if (time_cmp(wake_time, &queue_wake_time) > 0) + *wake_time = queue_wake_time; + } +} int timed_server (void *args, char *sub) { diff --git a/source/tcl_public.c b/source/tcl_public.c index e5f9a02..ba345d3 100644 --- a/source/tcl_public.c +++ b/source/tcl_public.c @@ -1480,46 +1480,24 @@ long time_left; } } -static struct timeval current; - -time_t tclTimerTimeout(time_t timeout) +void tclTimerTimeout(struct timeval *wake_time) { - register TimerList *stack = NULL; - long this_timeout = 0; + TimerList *stack = NULL; - if (timeout == 0) - return 0; - get_time(¤t); - if ((stack = tcl_Pending_timers)) - { - /* this is in minutes */ - for (; stack; stack = stack->next) - if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout) - timeout = this_timeout; - } - if ((stack = tcl_Pending_utimers)) - { - /* this is in seconds */ - for (; stack; stack = stack->next) - if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout) - timeout = this_timeout; - } -#if defined(WINNT) || defined(__EMX__) - return (timeout == MAGIC_TIMEOUT) ? MAGIC_TIMEOUT : timeout; -#else - return timeout; -#endif + /* this is in minutes */ + for (stack = tcl_Pending_timers; stack; stack = stack->next) + if (time_cmp(wake_time, &stack->time) > 0) + *wake_time = stack->time; + /* this is in seconds */ + for (stack = tcl_Pending_utimers; stack; stack = stack->next) + if (time_cmp(wake_time, &stack->time) > 0) + *wake_time = stack->time; } #else /* WANT_TCL */ -time_t tclTimerTimeout(time_t timeout) +void tclTimerTimeout(struct timeval *wake_time) { -#if defined(WINNT) || defined(__EMX__) - return (timeout == MAGIC_TIMEOUT) ? MAGIC_TIMEOUT : timeout; -#else - return timeout < MAGIC_TIMEOUT ? timeout : MAGIC_TIMEOUT; -#endif } int check_tcl_dcc(char *cmd, char *nick, char *host, int idx) diff --git a/source/timer.c b/source/timer.c index 419f9ca..7ad222b 100644 --- a/source/timer.c +++ b/source/timer.c @@ -600,25 +600,8 @@ static char *schedule_timer (TimerList *ntimer) * part of the call to select. */ -time_t TimerTimeout (void) +void TimerTimeout(struct timeval *wake_time) { - time_t timeout_in; - time_t t = MAGIC_TIMEOUT; - - if (is_server_queue() && (t = get_int_var(QUEUE_SENDS_VAR))) - ; - else - t = MAGIC_TIMEOUT; - if (!PendingTimers) - timeout_in = tclTimerTimeout(MAGIC_TIMEOUT); - else - { - timeout_in = (time_t)(time_until(&PendingTimers->time) * 1000); - timeout_in = (time_t)(tclTimerTimeout((timeout_in < 0) ? 0 : timeout_in)); - } - - if (t < timeout_in) - timeout_in = t * 1000; - - return (timeout_in < 0) ? 0 : timeout_in; + if (PendingTimers && time_cmp(wake_time, &PendingTimers->time) > 0) + *wake_time = PendingTimers->time; }