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>