Annotation of embedaddon/libevent/signal.c, revision 1.1

1.1     ! misho       1: /*     $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $       */
        !             2: 
        !             3: /*
        !             4:  * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  * 3. The name of the author may not be used to endorse or promote products
        !            16:  *    derived from this software without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            28:  */
        !            29: #ifdef HAVE_CONFIG_H
        !            30: #include "config.h"
        !            31: #endif
        !            32: 
        !            33: #ifdef WIN32
        !            34: #define WIN32_LEAN_AND_MEAN
        !            35: #include <winsock2.h>
        !            36: #include <windows.h>
        !            37: #undef WIN32_LEAN_AND_MEAN
        !            38: #endif
        !            39: #include <sys/types.h>
        !            40: #ifdef HAVE_SYS_TIME_H
        !            41: #include <sys/time.h>
        !            42: #endif
        !            43: #include <sys/queue.h>
        !            44: #ifdef HAVE_SYS_SOCKET_H
        !            45: #include <sys/socket.h>
        !            46: #endif
        !            47: #include <signal.h>
        !            48: #include <stdio.h>
        !            49: #include <stdlib.h>
        !            50: #include <string.h>
        !            51: #ifdef HAVE_UNISTD_H
        !            52: #include <unistd.h>
        !            53: #endif
        !            54: #include <errno.h>
        !            55: #ifdef HAVE_FCNTL_H
        !            56: #include <fcntl.h>
        !            57: #endif
        !            58: #include <assert.h>
        !            59: 
        !            60: #include "event.h"
        !            61: #include "event-internal.h"
        !            62: #include "evsignal.h"
        !            63: #include "evutil.h"
        !            64: #include "log.h"
        !            65: 
        !            66: struct event_base *evsignal_base = NULL;
        !            67: 
        !            68: static void evsignal_handler(int sig);
        !            69: 
        !            70: /* Callback for when the signal handler write a byte to our signaling socket */
        !            71: static void
        !            72: evsignal_cb(int fd, short what, void *arg)
        !            73: {
        !            74:        static char signals[1];
        !            75: #ifdef WIN32
        !            76:        SSIZE_T n;
        !            77: #else
        !            78:        ssize_t n;
        !            79: #endif
        !            80: 
        !            81:        n = recv(fd, signals, sizeof(signals), 0);
        !            82:        if (n == -1)
        !            83:                event_err(1, "%s: read", __func__);
        !            84: }
        !            85: 
        !            86: #ifdef HAVE_SETFD
        !            87: #define FD_CLOSEONEXEC(x) do { \
        !            88:         if (fcntl(x, F_SETFD, 1) == -1) \
        !            89:                 event_warn("fcntl(%d, F_SETFD)", x); \
        !            90: } while (0)
        !            91: #else
        !            92: #define FD_CLOSEONEXEC(x)
        !            93: #endif
        !            94: 
        !            95: int
        !            96: evsignal_init(struct event_base *base)
        !            97: {
        !            98:        int i;
        !            99: 
        !           100:        /* 
        !           101:         * Our signal handler is going to write to one end of the socket
        !           102:         * pair to wake up our event loop.  The event loop then scans for
        !           103:         * signals that got delivered.
        !           104:         */
        !           105:        if (evutil_socketpair(
        !           106:                    AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
        !           107: #ifdef WIN32
        !           108:                /* Make this nonfatal on win32, where sometimes people
        !           109:                   have localhost firewalled. */
        !           110:                event_warn("%s: socketpair", __func__);
        !           111: #else
        !           112:                event_err(1, "%s: socketpair", __func__);
        !           113: #endif
        !           114:                return -1;
        !           115:        }
        !           116: 
        !           117:        FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
        !           118:        FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
        !           119:        base->sig.sh_old = NULL;
        !           120:        base->sig.sh_old_max = 0;
        !           121:        base->sig.evsignal_caught = 0;
        !           122:        memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
        !           123:        /* initialize the queues for all events */
        !           124:        for (i = 0; i < NSIG; ++i)
        !           125:                TAILQ_INIT(&base->sig.evsigevents[i]);
        !           126: 
        !           127:         evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
        !           128: 
        !           129:        event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
        !           130:                EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
        !           131:        base->sig.ev_signal.ev_base = base;
        !           132:        base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
        !           133: 
        !           134:        return 0;
        !           135: }
        !           136: 
        !           137: /* Helper: set the signal handler for evsignal to handler in base, so that
        !           138:  * we can restore the original handler when we clear the current one. */
        !           139: int
        !           140: _evsignal_set_handler(struct event_base *base,
        !           141:                      int evsignal, void (*handler)(int))
        !           142: {
        !           143: #ifdef HAVE_SIGACTION
        !           144:        struct sigaction sa;
        !           145: #else
        !           146:        ev_sighandler_t sh;
        !           147: #endif
        !           148:        struct evsignal_info *sig = &base->sig;
        !           149:        void *p;
        !           150: 
        !           151:        /*
        !           152:         * resize saved signal handler array up to the highest signal number.
        !           153:         * a dynamic array is used to keep footprint on the low side.
        !           154:         */
        !           155:        if (evsignal >= sig->sh_old_max) {
        !           156:                int new_max = evsignal + 1;
        !           157:                event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
        !           158:                            __func__, evsignal, sig->sh_old_max));
        !           159:                p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
        !           160:                if (p == NULL) {
        !           161:                        event_warn("realloc");
        !           162:                        return (-1);
        !           163:                }
        !           164: 
        !           165:                memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
        !           166:                    0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
        !           167: 
        !           168:                sig->sh_old_max = new_max;
        !           169:                sig->sh_old = p;
        !           170:        }
        !           171: 
        !           172:        /* allocate space for previous handler out of dynamic array */
        !           173:        sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
        !           174:        if (sig->sh_old[evsignal] == NULL) {
        !           175:                event_warn("malloc");
        !           176:                return (-1);
        !           177:        }
        !           178: 
        !           179:        /* save previous handler and setup new handler */
        !           180: #ifdef HAVE_SIGACTION
        !           181:        memset(&sa, 0, sizeof(sa));
        !           182:        sa.sa_handler = handler;
        !           183:        sa.sa_flags |= SA_RESTART;
        !           184:        sigfillset(&sa.sa_mask);
        !           185: 
        !           186:        if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
        !           187:                event_warn("sigaction");
        !           188:                free(sig->sh_old[evsignal]);
        !           189:                sig->sh_old[evsignal] = NULL;
        !           190:                return (-1);
        !           191:        }
        !           192: #else
        !           193:        if ((sh = signal(evsignal, handler)) == SIG_ERR) {
        !           194:                event_warn("signal");
        !           195:                free(sig->sh_old[evsignal]);
        !           196:                sig->sh_old[evsignal] = NULL;
        !           197:                return (-1);
        !           198:        }
        !           199:        *sig->sh_old[evsignal] = sh;
        !           200: #endif
        !           201: 
        !           202:        return (0);
        !           203: }
        !           204: 
        !           205: int
        !           206: evsignal_add(struct event *ev)
        !           207: {
        !           208:        int evsignal;
        !           209:        struct event_base *base = ev->ev_base;
        !           210:        struct evsignal_info *sig = &ev->ev_base->sig;
        !           211: 
        !           212:        if (ev->ev_events & (EV_READ|EV_WRITE))
        !           213:                event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
        !           214:        evsignal = EVENT_SIGNAL(ev);
        !           215:        assert(evsignal >= 0 && evsignal < NSIG);
        !           216:        if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
        !           217:                event_debug(("%s: %p: changing signal handler", __func__, ev));
        !           218:                if (_evsignal_set_handler(
        !           219:                            base, evsignal, evsignal_handler) == -1)
        !           220:                        return (-1);
        !           221: 
        !           222:                /* catch signals if they happen quickly */
        !           223:                evsignal_base = base;
        !           224: 
        !           225:                if (!sig->ev_signal_added) {
        !           226:                        if (event_add(&sig->ev_signal, NULL))
        !           227:                                return (-1);
        !           228:                        sig->ev_signal_added = 1;
        !           229:                }
        !           230:        }
        !           231: 
        !           232:        /* multiple events may listen to the same signal */
        !           233:        TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
        !           234: 
        !           235:        return (0);
        !           236: }
        !           237: 
        !           238: int
        !           239: _evsignal_restore_handler(struct event_base *base, int evsignal)
        !           240: {
        !           241:        int ret = 0;
        !           242:        struct evsignal_info *sig = &base->sig;
        !           243: #ifdef HAVE_SIGACTION
        !           244:        struct sigaction *sh;
        !           245: #else
        !           246:        ev_sighandler_t *sh;
        !           247: #endif
        !           248: 
        !           249:        /* restore previous handler */
        !           250:        sh = sig->sh_old[evsignal];
        !           251:        sig->sh_old[evsignal] = NULL;
        !           252: #ifdef HAVE_SIGACTION
        !           253:        if (sigaction(evsignal, sh, NULL) == -1) {
        !           254:                event_warn("sigaction");
        !           255:                ret = -1;
        !           256:        }
        !           257: #else
        !           258:        if (signal(evsignal, *sh) == SIG_ERR) {
        !           259:                event_warn("signal");
        !           260:                ret = -1;
        !           261:        }
        !           262: #endif
        !           263:        free(sh);
        !           264: 
        !           265:        return ret;
        !           266: }
        !           267: 
        !           268: int
        !           269: evsignal_del(struct event *ev)
        !           270: {
        !           271:        struct event_base *base = ev->ev_base;
        !           272:        struct evsignal_info *sig = &base->sig;
        !           273:        int evsignal = EVENT_SIGNAL(ev);
        !           274: 
        !           275:        assert(evsignal >= 0 && evsignal < NSIG);
        !           276: 
        !           277:        /* multiple events may listen to the same signal */
        !           278:        TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next);
        !           279: 
        !           280:        if (!TAILQ_EMPTY(&sig->evsigevents[evsignal]))
        !           281:                return (0);
        !           282: 
        !           283:        event_debug(("%s: %p: restoring signal handler", __func__, ev));
        !           284: 
        !           285:        return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev)));
        !           286: }
        !           287: 
        !           288: static void
        !           289: evsignal_handler(int sig)
        !           290: {
        !           291:        int save_errno = errno;
        !           292: 
        !           293:        if (evsignal_base == NULL) {
        !           294:                event_warn(
        !           295:                        "%s: received signal %d, but have no base configured",
        !           296:                        __func__, sig);
        !           297:                return;
        !           298:        }
        !           299: 
        !           300:        evsignal_base->sig.evsigcaught[sig]++;
        !           301:        evsignal_base->sig.evsignal_caught = 1;
        !           302: 
        !           303: #ifndef HAVE_SIGACTION
        !           304:        signal(sig, evsignal_handler);
        !           305: #endif
        !           306: 
        !           307:        /* Wake up our notification mechanism */
        !           308:        send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
        !           309:        errno = save_errno;
        !           310: }
        !           311: 
        !           312: void
        !           313: evsignal_process(struct event_base *base)
        !           314: {
        !           315:        struct evsignal_info *sig = &base->sig;
        !           316:        struct event *ev, *next_ev;
        !           317:        sig_atomic_t ncalls;
        !           318:        int i;
        !           319:        
        !           320:        base->sig.evsignal_caught = 0;
        !           321:        for (i = 1; i < NSIG; ++i) {
        !           322:                ncalls = sig->evsigcaught[i];
        !           323:                if (ncalls == 0)
        !           324:                        continue;
        !           325:                sig->evsigcaught[i] -= ncalls;
        !           326: 
        !           327:                for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
        !           328:                    ev != NULL; ev = next_ev) {
        !           329:                        next_ev = TAILQ_NEXT(ev, ev_signal_next);
        !           330:                        if (!(ev->ev_events & EV_PERSIST))
        !           331:                                event_del(ev);
        !           332:                        event_active(ev, EV_SIGNAL, ncalls);
        !           333:                }
        !           334: 
        !           335:        }
        !           336: }
        !           337: 
        !           338: void
        !           339: evsignal_dealloc(struct event_base *base)
        !           340: {
        !           341:        int i = 0;
        !           342:        if (base->sig.ev_signal_added) {
        !           343:                event_del(&base->sig.ev_signal);
        !           344:                base->sig.ev_signal_added = 0;
        !           345:        }
        !           346:        for (i = 0; i < NSIG; ++i) {
        !           347:                if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
        !           348:                        _evsignal_restore_handler(base, i);
        !           349:        }
        !           350: 
        !           351:        if (base->sig.ev_signal_pair[0] != -1) {
        !           352:                EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
        !           353:                base->sig.ev_signal_pair[0] = -1;
        !           354:        }
        !           355:        if (base->sig.ev_signal_pair[1] != -1) {
        !           356:                EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
        !           357:                base->sig.ev_signal_pair[1] = -1;
        !           358:        }
        !           359:        base->sig.sh_old_max = 0;
        !           360: 
        !           361:        /* per index frees are handled in evsig_del() */
        !           362:        if (base->sig.sh_old) {
        !           363:                free(base->sig.sh_old);
        !           364:                base->sig.sh_old = NULL;
        !           365:        }
        !           366: }

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