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.
This commit is contained in:
Kevin Easton
2015-06-07 00:03:09 +10:00
parent 6f0f9dd8a8
commit c0c7cdbdcc
7 changed files with 67 additions and 99 deletions

View File

@@ -227,7 +227,7 @@ extern SGroup *server_group_list;
void BX_server_is_connected (int, int); void BX_server_is_connected (int, int);
int BX_parse_server_index (char *); int BX_parse_server_index (char *);
void BX_parse_server_info (char *, char **, char **, char **, 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_itsname (int, char *);
void BX_set_server_version (int, int); void BX_set_server_version (int, int);
char *BX_get_possible_umodes(int); char *BX_get_possible_umodes(int);

View File

@@ -19,6 +19,7 @@ typedef struct {
extern cmd_t C_msg[]; extern cmd_t C_msg[];
extern cmd_t C_dcc[]; extern cmd_t C_dcc[];
void tclTimerTimeout(struct timeval *wake_time);
int check_tcl_dcc (char *, char *, char *, int); int check_tcl_dcc (char *, char *, char *, int);
void tcl_command (char *, char *, char *, char *); void tcl_command (char *, char *, char *, char *);

View File

@@ -16,14 +16,9 @@ extern int kill_timer(char *);
extern void BX_delete_all_timers (void); extern void BX_delete_all_timers (void);
extern int timer_exists (char *ref); extern int timer_exists (char *ref);
void TimerTimeout(struct timeval *wake_time);
extern time_t TimerTimeout (void);
char *tcl_add_timer (TimerList **, long, char *, unsigned long); char *tcl_add_timer (TimerList **, long, char *, unsigned long);
int tcl_remove_timer (TimerList **, unsigned long); int tcl_remove_timer (TimerList **, unsigned long);
int timer_callback_exists(void *); int timer_callback_exists(void *);
time_t tclTimerTimeout(time_t);
#define MAGIC_TIMEOUT 100000000
#endif /* _TIMER_H_ */ #endif /* _TIMER_H_ */

View File

@@ -1196,13 +1196,10 @@ extern void set_screens (fd_set *, fd_set *);
void BX_io (const char *what) void BX_io (const char *what)
{ {
static int level = 0; static int level = 0;
long clock_timeout = 0, long clock_timeout = 0;
timer_timeout = 0, struct timeval my_now,
server_timeout = 0,
real_timeout = 0;
static struct timeval my_now,
my_timer, my_timer,
*time_ptr = &my_timer; timeout;
int hold_over, rc; int hold_over, rc;
fd_set rd, wd; fd_set rd, wd;
static int old_level = 0; static int old_level = 0;
@@ -1211,9 +1208,6 @@ void BX_io (const char *what)
level++; level++;
get_time(&my_now);
now = my_now.tv_sec;
if (x_debug & DEBUG_WAITS) if (x_debug & DEBUG_WAITS)
{ {
if (level != old_level) if (level != old_level)
@@ -1237,6 +1231,9 @@ void BX_io (const char *what)
caller[level] = what; caller[level] = what;
get_time(&my_now);
now = my_now.tv_sec;
/* CHECK FOR CPU SAVER MODE */ /* CHECK FOR CPU SAVER MODE */
if (!cpu_saver && get_int_var(CPU_SAVER_AFTER_VAR)) if (!cpu_saver && get_int_var(CPU_SAVER_AFTER_VAR))
if (now - idle_time > get_int_var(CPU_SAVER_AFTER_VAR) * 60) if (now - idle_time > get_int_var(CPU_SAVER_AFTER_VAR) * 60)
@@ -1250,7 +1247,6 @@ void BX_io (const char *what)
#ifndef GUI #ifndef GUI
set_screens(&rd, &wd); set_screens(&rd, &wd);
#endif #endif
server_timeout = set_server_bits(&rd, &wd);
set_process_bits(&rd); set_process_bits(&rd);
set_socket_read(&rd, &wd); set_socket_read(&rd, &wd);
set_nslookupfd(&rd); set_nslookupfd(&rd);
@@ -1258,37 +1254,39 @@ void BX_io (const char *what)
gui_setfd(&rd); gui_setfd(&rd);
#endif #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)) 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())) set_server_bits(&rd, &wd, &my_timer);
real_timeout = 0;
else if (timer_timeout <= clock_timeout)
real_timeout = timer_timeout;
else
real_timeout = clock_timeout;
if (server_timeout >= 0 && server_timeout < real_timeout) tclTimerTimeout(&my_timer);
real_timeout = server_timeout;
time_ptr = &my_timer; TimerTimeout(&my_timer);
if (real_timeout == -1) if ((hold_over = unhold_windows()) || time_cmp(&my_timer, &my_now) < 0)
time_ptr = NULL; {
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
else else
{ {
time_ptr->tv_sec = real_timeout / 1000; timeout.tv_sec = my_timer.tv_sec - my_now.tv_sec;
time_ptr->tv_usec = ((real_timeout % 1000) * 1000); 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 */ /* 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: case 0:
if (server_timeout >= 0)
do_idle_server(); do_idle_server();
break; break;
case -1: case -1:
@@ -1309,7 +1307,8 @@ void BX_io (const char *what)
default: default:
{ {
cntl_c_hit = 0; cntl_c_hit = 0;
now = time(NULL); get_time(&my_now);
now = my_now.tv_sec;
make_window_current(NULL); make_window_current(NULL);
do_server(&rd, &wd); do_server(&rd, &wd);
do_processes(&rd); 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(); ExecuteTimers();
#ifdef WANT_TCL #ifdef WANT_TCL
check_utimers(); check_utimers();

View File

@@ -227,19 +227,19 @@ void close_unattached_servers(void)
* set_server_bits: Sets the proper bits in the fd_set structure according to * 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. * 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; int i;
long timeout = -1;
for (i = 0; i < number_of_servers; i++) for (i = 0; i < number_of_servers; i++)
{ {
if (server_list[i].reconnect > 0) if (server_list[i].reconnect > 0)
{ {
/* CONNECT_DELAY is in seconds but we must struct timeval connect_wake_time = server_list[i].connect_time;
* return in milliseconds. connect_wake_time.tv_sec += get_int_var(CONNECT_DELAY_VAR);
*/
timeout = get_int_var(CONNECT_DELAY_VAR)*1000; if (time_cmp(wake_time, &connect_wake_time) > 0)
*wake_time = connect_wake_time;
} }
if (server_list[i].read > -1) 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); FD_SET(server_list[i].write, wr);
#endif #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) int timed_server (void *args, char *sub)
{ {

View File

@@ -1480,46 +1480,24 @@ long time_left;
} }
} }
static struct timeval current; void tclTimerTimeout(struct timeval *wake_time)
time_t tclTimerTimeout(time_t timeout)
{ {
register TimerList *stack = NULL; TimerList *stack = NULL;
long this_timeout = 0;
if (timeout == 0)
return 0;
get_time(&current);
if ((stack = tcl_Pending_timers))
{
/* this is in minutes */ /* this is in minutes */
for (; stack; stack = stack->next) for (stack = tcl_Pending_timers; stack; stack = stack->next)
if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout) if (time_cmp(wake_time, &stack->time) > 0)
timeout = this_timeout; *wake_time = stack->time;
}
if ((stack = tcl_Pending_utimers))
{
/* this is in seconds */ /* this is in seconds */
for (; stack; stack = stack->next) for (stack = tcl_Pending_utimers; stack; stack = stack->next)
if ((this_timeout = (BX_time_diff(current, stack->time)) * 1000) < timeout) if (time_cmp(wake_time, &stack->time) > 0)
timeout = this_timeout; *wake_time = stack->time;
}
#if defined(WINNT) || defined(__EMX__)
return (timeout == MAGIC_TIMEOUT) ? MAGIC_TIMEOUT : timeout;
#else
return timeout;
#endif
} }
#else /* WANT_TCL */ #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) int check_tcl_dcc(char *cmd, char *nick, char *host, int idx)

View File

@@ -600,25 +600,8 @@ static char *schedule_timer (TimerList *ntimer)
* part of the call to select. * part of the call to select.
*/ */
time_t TimerTimeout (void) void TimerTimeout(struct timeval *wake_time)
{ {
time_t timeout_in; if (PendingTimers && time_cmp(wake_time, &PendingTimers->time) > 0)
time_t t = MAGIC_TIMEOUT; *wake_time = PendingTimers->time;
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;
} }