X-Git-Url: https://git.decadent.org.uk/gitweb/?p=ion3.git;a=blobdiff_plain;f=libmainloop%2Fsignal.c;h=c5365532dd1b56d537d9150887df06a6b4385307;hp=fea01ba6ccabebb43ff9ded99c57707db64bef84;hb=HEAD;hpb=471a5e5f9928e2d324b2e10422a420f458bd63ff diff --git a/libmainloop/signal.c b/libmainloop/signal.c index fea01ba..c536553 100644 --- a/libmainloop/signal.c +++ b/libmainloop/signal.c @@ -1,12 +1,9 @@ /* * ion/libmainloop/signal.c * - * Copyright (c) Tuomo Valkonen 1999-2007. + * Copyright (c) Tuomo Valkonen 1999-2009. * - * Ion is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * See the included file LICENSE for details. */ #include @@ -17,6 +14,7 @@ #include #include #include +#include #include #include @@ -38,6 +36,8 @@ static bool had_tmr=FALSE; WHook *mainloop_sigchld_hook=NULL; WHook *mainloop_sigusr2_hook=NULL; +static sigset_t special_sigs; + /*{{{ Timers */ @@ -45,6 +45,34 @@ WHook *mainloop_sigusr2_hook=NULL; static WTimer *queue=NULL; +int mainloop_gettime(struct timeval *val) +{ +#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK>=0) + struct timespec spec; + int ret; + static int checked=0; + + if(checked>=0){ + ret=clock_gettime(CLOCK_MONOTONIC, &spec); + + if(ret==-1 && errno==EINVAL && checked==0){ + checked=-1; + }else{ + checked=1; + + val->tv_sec=spec.tv_sec; + val->tv_usec=spec.tv_nsec/1000; + + return ret; + } + } +#else + #warning "Monotonic clock unavailable; please fix your operating system." +#endif + return gettimeofday(val, NULL); +} + + #define TIMEVAL_LATER(a, b) \ ((a.tv_sec > b.tv_sec) || \ ((a.tv_sec == b.tv_sec) && \ @@ -53,44 +81,51 @@ static WTimer *queue=NULL; #define USECS_IN_SEC 1000000 -static void do_timer_set() +bool libmainloop_get_timeout(struct timeval *tv) { - struct itimerval val={{0, 0}, {0, 0}}; - - if(queue==NULL){ - setitimer(ITIMER_REAL, &val, NULL); - return; - } + if(queue==NULL) + return FALSE; /* Subtract queue time from current time, don't go below zero */ - gettimeofday(&(val.it_value), NULL); - if(TIMEVAL_LATER((queue)->when, val.it_value)){ - if(queue->when.tv_usecwhen.tv_usec+=USECS_IN_SEC; - queue->when.tv_sec--; + mainloop_gettime(tv); + if(TIMEVAL_LATER((queue)->when, (*tv))){ + if(queue->when.tv_usectv_usec){ + tv->tv_usec=(queue->when.tv_usec+USECS_IN_SEC)-tv->tv_usec; + /* TIMEVAL_LATER ensures >= 0 */ + tv->tv_sec=(queue->when.tv_sec-1)-tv->tv_sec; + }else{ + tv->tv_usec=queue->when.tv_usec-tv->tv_usec; + tv->tv_sec=queue->when.tv_sec-tv->tv_sec; } - val.it_value.tv_usec=queue->when.tv_usec-val.it_value.tv_usec; - val.it_value.tv_sec=queue->when.tv_sec-val.it_value.tv_sec; - if(val.it_value.tv_usec<0) - val.it_value.tv_usec=0; /* POSIX and some kernels have been designed by absolute morons and * contain idiotic artificial restrictions on the value of tv_usec, * that will only cause more code being run and clock cycles being * spent to do the same thing, as the kernel will in any case convert * the seconds to some other units. */ - val.it_value.tv_sec+=val.it_value.tv_usec/USECS_IN_SEC; - val.it_value.tv_usec%=USECS_IN_SEC; + tv->tv_sec+=tv->tv_usec/USECS_IN_SEC; + tv->tv_usec%=USECS_IN_SEC; }else{ had_tmr=TRUE; - return; + return FALSE; } + + return TRUE; +} + - val.it_interval.tv_usec=val.it_value.tv_usec; - val.it_interval.tv_sec=val.it_value.tv_sec; +static void do_timer_set() +{ + struct itimerval val={{0, 0}, {0, 0}}; - if((setitimer(ITIMER_REAL, &val, NULL))){ - had_tmr=TRUE; + if(libmainloop_get_timeout(&val.it_value)){ + val.it_interval.tv_usec=0; + val.it_interval.tv_sec=0; + + if((setitimer(ITIMER_REAL, &val, NULL))) + had_tmr=TRUE; + }else if(!had_tmr){ + setitimer(ITIMER_REAL, &val, NULL); } } @@ -191,9 +226,11 @@ bool mainloop_check_signals() return kill_sig; /* Check for timer events in the queue */ - while(had_tmr && queue!=NULL){ + while(had_tmr){ had_tmr=FALSE; - gettimeofday(¤t_time, NULL); + if(queue==NULL) + break; + mainloop_gettime(¤t_time); while(queue!=NULL){ if(TIMEVAL_LATER(current_time, queue->when)){ q=queue; @@ -224,11 +261,23 @@ bool mainloop_check_signals() } +void mainloop_block_signals(sigset_t *oldmask) +{ + sigprocmask(SIG_BLOCK, &special_sigs, oldmask); +} + + +bool mainloop_unhandled_signals() +{ + return (usr2_sig || wait_sig || kill_sig || had_tmr); +} + + static void add_to_current_time(struct timeval *when, uint msecs) { long tmp_usec; - gettimeofday(when, NULL); + mainloop_gettime(when); tmp_usec=when->tv_usec + (msecs * 1000); when->tv_usec=tmp_usec % 1000000; when->tv_sec+=tmp_usec / 1000000; @@ -449,6 +498,7 @@ static void ignore_handler(int signal_num) #define FATAL(X) IFTRAP(X) signal(X, fatal_signal_handler); #define IGNORE(X) IFTRAP(X) signal(X, SIG_IGN) + void mainloop_trap_signals(const sigset_t *which) { struct sigaction sa; @@ -460,6 +510,7 @@ void mainloop_trap_signals(const sigset_t *which) which=&dummy; } + sigemptyset(&special_sigs); sigemptyset(&set); sigemptyset(&oldset); sigprocmask(SIG_SETMASK, &set, &oldset); @@ -483,24 +534,28 @@ void mainloop_trap_signals(const sigset_t *which) sa.sa_handler=timer_handler; sa.sa_flags=SA_RESTART; sigaction(SIGALRM, &sa, NULL); + sigaddset(&special_sigs, SIGALRM); } IFTRAP(SIGCHLD){ sa.sa_handler=chld_handler; sa.sa_flags=SA_NOCLDSTOP|SA_RESTART; sigaction(SIGCHLD, &sa, NULL); + sigaddset(&special_sigs, SIGCHLD); } IFTRAP(SIGUSR2){ sa.sa_handler=usr2_handler; sa.sa_flags=SA_RESTART; sigaction(SIGUSR2, &sa, NULL); + sigaddset(&special_sigs, SIGUSR2); } IFTRAP(SIGTERM){ sa.sa_handler=exit_handler; sa.sa_flags=SA_RESTART; sigaction(SIGTERM, &sa, NULL); + sigaddset(&special_sigs, SIGTERM); } IFTRAP(SIGUSR1){