File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / sigevent.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:39 2013 UTC (11 years, 1 month ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>