/*
* ion/libmainloop/signal.c
*
- * Copyright (c) Tuomo Valkonen 1999-2007.
+ * Copyright (c) Tuomo Valkonen 1999-2008.
*
* See the included file LICENSE for details.
*/
#include <signal.h>
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <libtu/objp.h>
#include <libtu/types.h>
WHook *mainloop_sigchld_hook=NULL;
WHook *mainloop_sigusr2_hook=NULL;
+static sigset_t special_sigs;
+
/*{{{ Timers */
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) && \
#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_usec<val.it_value.tv_usec){
+ mainloop_gettime(tv);
+ if(TIMEVAL_LATER((queue)->when, (*tv))){
+ if(queue->when.tv_usec<tv->tv_usec){
queue->when.tv_usec+=USECS_IN_SEC;
queue->when.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;
+ tv->tv_usec=queue->when.tv_usec-tv->tv_usec;
+ tv->tv_sec=queue->when.tv_sec-tv->tv_sec;
+ if(tv->tv_usec<0)
+ tv->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);
}
}
/* Check for timer events in the queue */
while(had_tmr && queue!=NULL){
had_tmr=FALSE;
- gettimeofday(¤t_time, NULL);
+ mainloop_gettime(¤t_time);
while(queue!=NULL){
if(TIMEVAL_LATER(current_time, queue->when)){
q=queue;
}
+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;
#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;
which=&dummy;
}
+ sigemptyset(&special_sigs);
sigemptyset(&set);
sigemptyset(&oldset);
sigprocmask(SIG_SETMASK, &set, &oldset);
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){