Annotation of embedaddon/quagga/lib/sigevent.c, revision 1.1
1.1 ! misho 1: /* Quagga signal handling functions.
! 2: * Copyright (C) 2004 Paul Jakma,
! 3: *
! 4: * This file is part of Quagga.
! 5: *
! 6: * Quagga is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2, or (at your option) any
! 9: * later version.
! 10: *
! 11: * Quagga is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of
! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 14: * General Public License for more details.
! 15: *
! 16: * You should have received a copy of the GNU General Public License
! 17: * along with Quagga; see the file COPYING. If not, write to the Free
! 18: * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
! 19: * 02111-1307, USA.
! 20: */
! 21:
! 22: #include <zebra.h>
! 23: #include <sigevent.h>
! 24: #include <log.h>
! 25:
! 26: #ifdef SA_SIGINFO
! 27: #ifdef HAVE_UCONTEXT_H
! 28: #ifdef GNU_LINUX
! 29: /* get REG_EIP from ucontext.h */
! 30: #ifndef __USE_GNU
! 31: #define __USE_GNU
! 32: #endif /* __USE_GNU */
! 33: #endif /* GNU_LINUX */
! 34: #include <ucontext.h>
! 35: #endif /* HAVE_UCONTEXT_H */
! 36: #endif /* SA_SIGINFO */
! 37:
! 38:
! 39: /* master signals descriptor struct */
! 40: struct quagga_sigevent_master_t
! 41: {
! 42: struct thread *t;
! 43:
! 44: struct quagga_signal_t *signals;
! 45: int sigc;
! 46:
! 47: volatile sig_atomic_t caught;
! 48: } sigmaster;
! 49:
! 50: /* Generic signal handler
! 51: * Schedules signal event thread
! 52: */
! 53: static void
! 54: quagga_signal_handler (int signo)
! 55: {
! 56: int i;
! 57: struct quagga_signal_t *sig;
! 58:
! 59: for (i = 0; i < sigmaster.sigc; i++)
! 60: {
! 61: sig = &(sigmaster.signals[i]);
! 62:
! 63: if (sig->signal == signo)
! 64: sig->caught = 1;
! 65: }
! 66:
! 67: sigmaster.caught = 1;
! 68: }
! 69:
! 70: /* check if signals have been caught and run appropriate handlers */
! 71: int
! 72: quagga_sigevent_process (void)
! 73: {
! 74: struct quagga_signal_t *sig;
! 75: int i;
! 76: #ifdef SIGEVENT_BLOCK_SIGNALS
! 77: /* shouldnt need to block signals, but potentially may be needed */
! 78: sigset_t newmask, oldmask;
! 79:
! 80: /*
! 81: * Block most signals, but be careful not to defer SIGTRAP because
! 82: * doing so breaks gdb, at least on NetBSD 2.0. Avoid asking to
! 83: * block SIGKILL, just because we shouldn't be able to do so.
! 84: */
! 85: sigfillset (&newmask);
! 86: sigdelset (&newmask, SIGTRAP);
! 87: sigdelset (&newmask, SIGKILL);
! 88:
! 89: if ( (sigprocmask (SIG_BLOCK, &newmask, &oldmask)) < 0)
! 90: {
! 91: zlog_err ("quagga_signal_timer: couldnt block signals!");
! 92: return -1;
! 93: }
! 94: #endif /* SIGEVENT_BLOCK_SIGNALS */
! 95:
! 96: if (sigmaster.caught > 0)
! 97: {
! 98: sigmaster.caught = 0;
! 99: /* must not read or set sigmaster.caught after here,
! 100: * race condition with per-sig caught flags if one does
! 101: */
! 102:
! 103: for (i = 0; i < sigmaster.sigc; i++)
! 104: {
! 105: sig = &(sigmaster.signals[i]);
! 106:
! 107: if (sig->caught > 0)
! 108: {
! 109: sig->caught = 0;
! 110: sig->handler ();
! 111: }
! 112: }
! 113: }
! 114:
! 115: #ifdef SIGEVENT_BLOCK_SIGNALS
! 116: if ( sigprocmask (SIG_UNBLOCK, &oldmask, NULL) < 0 );
! 117: return -1;
! 118: #endif /* SIGEVENT_BLOCK_SIGNALS */
! 119:
! 120: return 0;
! 121: }
! 122:
! 123: #ifdef SIGEVENT_SCHEDULE_THREAD
! 124: /* timer thread to check signals. Shouldnt be needed */
! 125: int
! 126: quagga_signal_timer (struct thread *t)
! 127: {
! 128: struct quagga_sigevent_master_t *sigm;
! 129: struct quagga_signal_t *sig;
! 130: int i;
! 131:
! 132: sigm = THREAD_ARG (t);
! 133: sigm->t = thread_add_timer (sigm->t->master, quagga_signal_timer, &sigmaster,
! 134: QUAGGA_SIGNAL_TIMER_INTERVAL);
! 135: return quagga_sigevent_process ();
! 136: }
! 137: #endif /* SIGEVENT_SCHEDULE_THREAD */
! 138:
! 139: /* Initialization of signal handles. */
! 140: /* Signal wrapper. */
! 141: static int
! 142: signal_set (int signo)
! 143: {
! 144: int ret;
! 145: struct sigaction sig;
! 146: struct sigaction osig;
! 147:
! 148: sig.sa_handler = &quagga_signal_handler;
! 149: sigfillset (&sig.sa_mask);
! 150: sig.sa_flags = 0;
! 151: if (signo == SIGALRM) {
! 152: #ifdef SA_INTERRUPT
! 153: sig.sa_flags |= SA_INTERRUPT; /* SunOS */
! 154: #endif
! 155: } else {
! 156: #ifdef SA_RESTART
! 157: sig.sa_flags |= SA_RESTART;
! 158: #endif /* SA_RESTART */
! 159: }
! 160:
! 161: ret = sigaction (signo, &sig, &osig);
! 162: if (ret < 0)
! 163: return ret;
! 164: else
! 165: return 0;
! 166: }
! 167:
! 168: #ifdef SA_SIGINFO
! 169:
! 170: /* XXX This function should be enhanced to support more platforms
! 171: (it currently works only on Linux/x86). */
! 172: static void *
! 173: program_counter(void *context)
! 174: {
! 175: #ifdef HAVE_UCONTEXT_H
! 176: #ifdef GNU_LINUX
! 177: #ifdef REG_EIP
! 178: if (context)
! 179: return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]);
! 180: #endif /* REG_EIP */
! 181: #endif /* GNU_LINUX */
! 182: #endif /* HAVE_UCONTEXT_H */
! 183: return NULL;
! 184: }
! 185:
! 186: #endif /* SA_SIGINFO */
! 187:
! 188: static void __attribute__ ((noreturn))
! 189: exit_handler(int signo
! 190: #ifdef SA_SIGINFO
! 191: , siginfo_t *siginfo, void *context
! 192: #endif
! 193: )
! 194: {
! 195: zlog_signal(signo, "exiting..."
! 196: #ifdef SA_SIGINFO
! 197: , siginfo, program_counter(context)
! 198: #endif
! 199: );
! 200: _exit(128+signo);
! 201: }
! 202:
! 203: static void __attribute__ ((noreturn))
! 204: core_handler(int signo
! 205: #ifdef SA_SIGINFO
! 206: , siginfo_t *siginfo, void *context
! 207: #endif
! 208: )
! 209: {
! 210: zlog_signal(signo, "aborting..."
! 211: #ifdef SA_SIGINFO
! 212: , siginfo, program_counter(context)
! 213: #endif
! 214: );
! 215: abort();
! 216: }
! 217:
! 218: static void
! 219: trap_default_signals(void)
! 220: {
! 221: static const int core_signals[] = {
! 222: SIGQUIT,
! 223: SIGILL,
! 224: #ifdef SIGEMT
! 225: SIGEMT,
! 226: #endif
! 227: SIGFPE,
! 228: SIGBUS,
! 229: SIGSEGV,
! 230: #ifdef SIGSYS
! 231: SIGSYS,
! 232: #endif
! 233: #ifdef SIGXCPU
! 234: SIGXCPU,
! 235: #endif
! 236: #ifdef SIGXFSZ
! 237: SIGXFSZ,
! 238: #endif
! 239: };
! 240: static const int exit_signals[] = {
! 241: SIGHUP,
! 242: SIGINT,
! 243: SIGALRM,
! 244: SIGTERM,
! 245: SIGUSR1,
! 246: SIGUSR2,
! 247: #ifdef SIGPOLL
! 248: SIGPOLL,
! 249: #endif
! 250: #ifdef SIGVTALRM
! 251: SIGVTALRM,
! 252: #endif
! 253: #ifdef SIGSTKFLT
! 254: SIGSTKFLT,
! 255: #endif
! 256: };
! 257: static const int ignore_signals[] = {
! 258: SIGPIPE,
! 259: };
! 260: static const struct {
! 261: const int *sigs;
! 262: u_int nsigs;
! 263: void (*handler)(int signo
! 264: #ifdef SA_SIGINFO
! 265: , siginfo_t *info, void *context
! 266: #endif
! 267: );
! 268: } sigmap[] = {
! 269: { core_signals, sizeof(core_signals)/sizeof(core_signals[0]), core_handler},
! 270: { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]), exit_handler},
! 271: { ignore_signals, sizeof(ignore_signals)/sizeof(ignore_signals[0]), NULL},
! 272: };
! 273: u_int i;
! 274:
! 275: for (i = 0; i < sizeof(sigmap)/sizeof(sigmap[0]); i++)
! 276: {
! 277: u_int j;
! 278:
! 279: for (j = 0; j < sigmap[i].nsigs; j++)
! 280: {
! 281: struct sigaction oact;
! 282: if ((sigaction(sigmap[i].sigs[j],NULL,&oact) == 0) &&
! 283: (oact.sa_handler == SIG_DFL))
! 284: {
! 285: struct sigaction act;
! 286: sigfillset (&act.sa_mask);
! 287: if (sigmap[i].handler == NULL)
! 288: {
! 289: act.sa_handler = SIG_IGN;
! 290: act.sa_flags = 0;
! 291: }
! 292: else
! 293: {
! 294: #ifdef SA_SIGINFO
! 295: /* Request extra arguments to signal handler. */
! 296: act.sa_sigaction = sigmap[i].handler;
! 297: act.sa_flags = SA_SIGINFO;
! 298: #else
! 299: act.sa_handler = sigmap[i].handler;
! 300: act.sa_flags = 0;
! 301: #endif
! 302: }
! 303: if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
! 304: zlog_warn("Unable to set signal handler for signal %d: %s",
! 305: sigmap[i].sigs[j],safe_strerror(errno));
! 306:
! 307: }
! 308: }
! 309: }
! 310: }
! 311:
! 312: void
! 313: signal_init (struct thread_master *m, int sigc,
! 314: struct quagga_signal_t signals[])
! 315: {
! 316:
! 317: int i = 0;
! 318: struct quagga_signal_t *sig;
! 319:
! 320: /* First establish some default handlers that can be overridden by
! 321: the application. */
! 322: trap_default_signals();
! 323:
! 324: while (i < sigc)
! 325: {
! 326: sig = &signals[i];
! 327: if ( signal_set (sig->signal) < 0 )
! 328: exit (-1);
! 329: i++;
! 330: }
! 331:
! 332: sigmaster.sigc = sigc;
! 333: sigmaster.signals = signals;
! 334:
! 335: #ifdef SIGEVENT_SCHEDULE_THREAD
! 336: sigmaster.t =
! 337: thread_add_timer (m, quagga_signal_timer, &sigmaster,
! 338: QUAGGA_SIGNAL_TIMER_INTERVAL);
! 339: #endif /* SIGEVENT_SCHEDULE_THREAD */
! 340: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>