Allow SIGIO to unblock poll() without dying

This commit is contained in:
Jeremy Lakeman 2015-06-01 16:46:21 +09:30
parent d5b96b9931
commit a3de276999
2 changed files with 59 additions and 31 deletions

View File

@ -339,48 +339,57 @@ int fd_poll2(time_ms_t (*waiting)(time_ms_t, time_ms_t, time_ms_t), void (*wokeu
RETURN(1);
}
// return 0 when there's nothing to do, it doesn't make sense to wait for infinity
if (!run_now && !wake_list && fdcount==0)
RETURN(0);
time_ms_t wait;
time_ms_t now = gettime_ms();
time_ms_t wait_until=TIME_MS_NEVER_WILL;
uint8_t called_waiting = 0;
if (run_now)
wait = 0;
else {
if (run_now){
wait_until = now;
}else{
time_ms_t next_run=TIME_MS_NEVER_WILL;
if(run_soon)
next_run = run_soon->run_after;
time_ms_t next_wake=TIME_MS_NEVER_WILL;
if (wake_list)
next_wake = wake_list->wake_at;
time_ms_t wait_until;
time_ms_t now = gettime_ms();
if (waiting)
wait_until = waiting(now, next_run, next_wake);
else
wait_until = next_wake;
if (wait_until==TIME_MS_NEVER_WILL)
wait = -1;
else if (wait_until < now)
wait = 0;
else
wait = wait_until - now;
wait_until = wake_list->wake_at;
if (waiting && wait_until > now){
wait_until = waiting(now, next_run, wait_until);
now = gettime_ms();
called_waiting = 1;
}
}
// check for IO and/or wait for the next wake_at
int wait=0;
int r=0;
if (fdcount || wait>0){
{
struct call_stats call_stats;
call_stats.totals=&poll_stats;
fd_func_enter(__HERE__, &call_stats);
if (fdcount==0){
sleep_ms(wait);
}else{
if (wait_until==TIME_MS_NEVER_WILL)
wait = -1;
else if (wait_until <= now)
wait = 0;
else
wait = wait_until - now;
if (fdcount){
if (config.debug.io)
DEBUGF("Calling poll with %dms wait", wait);
fd_func_enter(__HERE__, &call_stats);
r = poll(fds, fdcount, wait);
fd_func_exit(__HERE__, &call_stats);
if (r==-1 && errno!=EINTR)
WHY_perror("poll");
if (config.debug.io) {
strbuf b = strbuf_alloca(1024);
int i;
@ -394,11 +403,16 @@ int fd_poll2(time_ms_t (*waiting)(time_ms_t, time_ms_t, time_ms_t), void (*wokeu
}
DEBUGF("poll(fds=(%s), fdcount=%d, ms=%d) -> %d", strbuf_str(b), fdcount, wait, r);
}
}else if(wait>0){
fd_func_enter(__HERE__, &call_stats);
sleep_ms(wait);
fd_func_exit(__HERE__, &call_stats);
}
fd_func_exit(__HERE__, &call_stats);
}
if (wokeup && !run_now)
if (wokeup && called_waiting)
wokeup();
move_run_list();

View File

@ -252,13 +252,24 @@ static int server_bind()
/* Catch SIGHUP etc so that we can respond to requests to do things, eg, shut down. */
struct sigaction sig;
bzero(&sig, sizeof sig);
sig.sa_flags = 0;
sig.sa_handler = signal_handler;
sigemptyset(&sig.sa_mask); // Block the same signals during handler
sigaddset(&sig.sa_mask, SIGHUP);
sigaddset(&sig.sa_mask, SIGINT);
sig.sa_flags = 0;
sigaddset(&sig.sa_mask, SIGIO);
#ifdef ANDROID
// batphone depends on this constant to wake up the scheduler
// break the build if it changes.
assert(SIGIO==29);
#endif
sigaction(SIGHUP, &sig, NULL);
sigaction(SIGINT, &sig, NULL);
sigaction(SIGIO, &sig, NULL);
/* Setup up client API sockets before writing our PID file
We want clients to be able to connect to our sockets as soon
@ -303,7 +314,7 @@ static int server_bind()
time_ms_t now = gettime_ms();
// Periodically check for server shut down
RESCHEDULE(&ALARM_STRUCT(server_shutdown_check), now, now+30000, now);
RESCHEDULE(&ALARM_STRUCT(server_shutdown_check), now, TIME_MS_NEVER_WILL, now);
overlay_mdp_bind_internal_services();
@ -599,7 +610,7 @@ void server_shutdown_check(struct sched_ent *alarm)
}
}
if (alarm){
RESCHEDULE(alarm, now+1000, now+30000, now+1100);
RESCHEDULE(alarm, now+1000, TIME_MS_NEVER_WILL, now+1100);
}
}
@ -639,6 +650,9 @@ static void serverCleanUp()
static void signal_handler(int signal)
{
switch (signal) {
case SIGIO:
// noop to break out of poll
return;
case SIGHUP:
case SIGINT:
/* Trigger the server to close gracefully after any current alarm has completed.