diff options
-rw-r--r-- | lib/ChangeLog | 17 | ||||
-rw-r--r-- | lib/sigevent.c | 83 | ||||
-rw-r--r-- | lib/sigevent.h | 4 | ||||
-rw-r--r-- | lib/thread.c | 42 |
4 files changed, 100 insertions, 46 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog index 108a2023..b3d452e0 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,20 @@ +2004-07-14 Paul Jakma <paul@dishone.st> + + * sigevent.c: (quagga_signal_handler) add a global caught flag, set + the flags to a constant rather increment to be kinder. + (quagga_sigevent_process) new function, to do core of what + quagga_signal_timer did. dont block signals at all as sig->caught + is volatile sig_atomic_t and should be safe to access from signal + and normal contexts. The signal blocking is unneeded paranoia, but + is left intact under an ifdef, should some platform require it. + Check global caught flag before iterating through array. + (quagga_signal_timer) nearly everything moved to + quagga_sigevent_process. Left in under ifdef, in case some + platform could use a regular timer check for signals. + * sigevent.h: quagga_sigevent_process declaration. + * thread.c: (thread_fetch) check for signals at beginning of + scheduler loop, check for signals if select returns EINTR. + 2004-07-13 Greg Troxel <gdt@poblano.ir.bbn.com> * sigevent.c: Don't block SIGTRAP and SIGKILL. Blocking SIGTRAP diff --git a/lib/sigevent.c b/lib/sigevent.c index 6a2fd80c..937180c9 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -23,15 +23,16 @@ #include <sigevent.h> #include <log.h> +/* master signals descriptor struct */ struct quagga_sigevent_master_t { - struct thread_master *tm; struct thread *t; - struct quagga_signal_t *signals; + struct quagga_signal_t *signals; int sigc; - -} sigmaster; + + volatile sig_atomic_t caught; +} sigmaster; /* Generic signal handler * Schedules signal event thread @@ -47,20 +48,22 @@ quagga_signal_handler (int signo) sig = &(sigmaster.signals[i]); if (sig->signal == signo) - sig->caught++; + sig->caught = 1; } + + sigmaster.caught = 1; } +/* check if signals have been caught and run appropriate handlers */ int -quagga_signal_timer (struct thread *t) +quagga_sigevent_process (void) { - sigset_t newmask, oldmask; - struct quagga_sigevent_master_t *sigm; struct quagga_signal_t *sig; int i; +#ifdef SIGEVENT_BLOCK_SIGNALS + /* shouldnt need to block signals, but potentially may be needed */ + sigset_t newmask, oldmask; - sigm = THREAD_ARG (t); - /* * Block most signals, but be careful not to defer SIGTRAP because * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to @@ -69,34 +72,57 @@ quagga_signal_timer (struct thread *t) sigfillset (&newmask); sigdelset (&newmask, SIGTRAP); sigdelset (&newmask, SIGKILL); - + if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0) { zlog_err ("quagga_signal_timer: couldnt block signals!"); - sigm->t = thread_add_timer (sigm->tm, quagga_signal_timer, - &sigmaster, QUAGGA_SIGNAL_TIMER_INTERVAL); return -1; } - - for (i = 0; i < sigm->sigc; i++) +#endif /* SIGEVENT_BLOCK_SIGNALS */ + + if (sigmaster.caught > 0) { - sig = &(sigm->signals[i]); - if (sig->caught > 0) + sigmaster.caught = 0; + /* must not read or set sigmaster.caught after here, + * race condition with per-sig caught flags if one does + */ + + for (i = 0; i < sigmaster.sigc; i++) { - sig->caught = 0; - sig->handler(); + sig = &(sigmaster.signals[i]); + + if (sig->caught > 0) + { + sig->caught = 0; + sig->handler (); + } } } - - sigm->t = thread_add_timer (sigm->tm, quagga_signal_timer, &sigmaster, - QUAGGA_SIGNAL_TIMER_INTERVAL); +#ifdef SIGEVENT_BLOCK_SIGNALS if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 ); return -1; - +#endif /* SIGEVENT_BLOCK_SIGNALS */ + return 0; } +#ifdef SIGEVENT_SCHEDULE_THREAD +/* timer thread to check signals. Shouldnt be needed */ +int +quagga_signal_timer (struct thread *t) +{ + struct quagga_sigevent_master_t *sigm; + struct quagga_signal_t *sig; + int i; + + sigm = THREAD_ARG (t); + sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster, + QUAGGA_SIGNAL_TIMER_INTERVAL); + return quagga_sigevent_process (); +} +#endif /* SIGEVENT_SCHEDULE_THREAD */ + /* Initialization of signal handles. */ /* Signale wrapper. */ int @@ -127,8 +153,8 @@ signal_set (int signo) } void -signal_init (struct thread_master *m, - int sigc, struct quagga_signal_t signals[]) +signal_init (struct thread_master *m, int sigc, + struct quagga_signal_t signals[]) { int i = 0; @@ -144,11 +170,10 @@ signal_init (struct thread_master *m, sigmaster.sigc = sigc; sigmaster.signals = signals; - sigmaster.tm = m; - + +#ifdef SIGEVENT_SCHEDULE_THREAD sigmaster.t = thread_add_timer (m, quagga_signal_timer, &sigmaster, QUAGGA_SIGNAL_TIMER_INTERVAL); - +#endif /* SIGEVENT_SCHEDULE_THREAD */ } - diff --git a/lib/sigevent.h b/lib/sigevent.h index 6296736a..20012aff 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -23,6 +23,7 @@ #ifndef _QUAGGA_SIGNAL_H #define _QUAGGA_SIGNAL_H + #include <thread.h> #define QUAGGA_SIGNAL_TIMER_INTERVAL 2L @@ -46,4 +47,7 @@ struct quagga_signal_t void signal_init (struct thread_master *m, int sigc, struct quagga_signal_t *signals); +/* check whether there are signals to handle, process any found */ +int quagga_sigevent_process (void); + #endif /* _QUAGGA_SIGNAL_H */ diff --git a/lib/thread.c b/lib/thread.c index 93809f2f..2e953c55 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -28,6 +28,7 @@ #include "log.h" #include "hash.h" #include "command.h" +#include "sigevent.h" static struct hash *cpu_record = NULL; @@ -748,23 +749,26 @@ thread_fetch (struct thread_master *m, struct thread *fetch) while (1) { - /* Normal event is the highest priority. */ + /* Signals are highest priority */ + quagga_sigevent_process (); + + /* Normal event are the next highest priority. */ if ((thread = thread_trim_head (&m->event)) != NULL) - return thread_run (m, thread, fetch); + return thread_run (m, thread, fetch); /* Execute timer. */ gettimeofday (&timer_now, NULL); for (thread = m->timer.head; thread; thread = thread->next) - if (timeval_cmp (timer_now, thread->u.sands) >= 0) - { - thread_list_delete (&m->timer, thread); - return thread_run (m, thread, fetch); - } + if (timeval_cmp (timer_now, thread->u.sands) >= 0) + { + thread_list_delete (&m->timer, thread); + return thread_run (m, thread, fetch); + } /* If there are any ready threads, process top of them. */ if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + return thread_run (m, thread, fetch); /* Structure copy. */ readfd = m->readfd; @@ -777,16 +781,20 @@ thread_fetch (struct thread_master *m, struct thread *fetch) num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait); if (num == 0) - continue; + continue; if (num < 0) - { - if (errno == EINTR) - continue; - - zlog_warn ("select() error: %s", strerror (errno)); - return NULL; - } + { + if (errno == EINTR) + { + /* signal received */ + quagga_sigevent_process (); + continue; + } + + zlog_warn ("select() error: %s", strerror (errno)); + return NULL; + } /* Normal priority read thead. */ ready = thread_process_fd (m, &m->read, &readfd, &m->readfd); @@ -795,7 +803,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch) ready = thread_process_fd (m, &m->write, &writefd, &m->writefd); if ((thread = thread_trim_head (&m->ready)) != NULL) - return thread_run (m, thread, fetch); + return thread_run (m, thread, fetch); } } |