root/opal/mca/event/libevent2022/libevent/signal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. evsig_set_base
  2. evsig_cb
  3. evsig_init
  4. _evsig_set_handler
  5. evsig_add
  6. _evsig_restore_handler
  7. evsig_del
  8. evsig_handler
  9. evsig_dealloc
  10. evsig_global_setup_locks_

   1 /*      $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $       */
   2 
   3 /*
   4  * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
   5  * Copyright 2007-2012 Niels Provos and Nick Mathewson
   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 #include "event2/event-config.h"
  30 
  31 #ifdef WIN32
  32 #define WIN32_LEAN_AND_MEAN
  33 #include <winsock2.h>
  34 #include <windows.h>
  35 #undef WIN32_LEAN_AND_MEAN
  36 #endif
  37 #include <sys/types.h>
  38 #ifdef _EVENT_HAVE_SYS_TIME_H
  39 #include <sys/time.h>
  40 #endif
  41 #include <sys/queue.h>
  42 #ifdef _EVENT_HAVE_SYS_SOCKET_H
  43 #include <sys/socket.h>
  44 #endif
  45 #include <signal.h>
  46 #include <stdio.h>
  47 #include <stdlib.h>
  48 #include <string.h>
  49 #ifdef _EVENT_HAVE_UNISTD_H
  50 #include <unistd.h>
  51 #endif
  52 #include <errno.h>
  53 #ifdef _EVENT_HAVE_FCNTL_H
  54 #include <fcntl.h>
  55 #endif
  56 
  57 #include "event2/event.h"
  58 #include "event2/event_struct.h"
  59 #include "event-internal.h"
  60 #include "event2/util.h"
  61 #include "evsignal-internal.h"
  62 #include "log-internal.h"
  63 #include "evmap-internal.h"
  64 #include "evthread-internal.h"
  65 
  66 /*
  67   signal.c
  68 
  69   This is the signal-handling implementation we use for backends that don't
  70   have a better way to do signal handling.  It uses sigaction() or signal()
  71   to set a signal handler, and a socket pair to tell the event base when
  72 
  73   Note that I said "the event base" : only one event base can be set up to use
  74   this at a time.  For historical reasons and backward compatibility, if you
  75   add an event for a signal to event_base A, then add an event for a signal
  76   (any signal!) to event_base B, event_base B will get informed about the
  77   signal, but event_base A won't.
  78 
  79   It would be neat to change this behavior in some future version of Libevent.
  80   kqueue already does something far more sensible.  We can make all backends
  81   on Linux do a reasonable thing using signalfd.
  82 */
  83 
  84 #ifndef WIN32
  85 /* Windows wants us to call our signal handlers as __cdecl.  Nobody else
  86  * expects you to do anything crazy like this. */
  87 #define __cdecl
  88 #endif
  89 
  90 static int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
  91 static int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
  92 
  93 static const struct eventop evsigops = {
  94         "signal",
  95         NULL,
  96         evsig_add,
  97         evsig_del,
  98         NULL,
  99         NULL,
 100         0, 0, 0
 101 };
 102 
 103 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
 104 /* Lock for evsig_base and evsig_base_n_signals_added fields. */
 105 static void *evsig_base_lock = NULL;
 106 #endif
 107 /* The event base that's currently getting informed about signals. */
 108 static struct event_base *evsig_base = NULL;
 109 /* A copy of evsig_base->sigev_n_signals_added. */
 110 static int evsig_base_n_signals_added = 0;
 111 static evutil_socket_t evsig_base_fd = -1;
 112 
 113 static void __cdecl evsig_handler(int sig);
 114 
 115 #define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
 116 #define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
 117 
 118 void
 119 evsig_set_base(struct event_base *base)
 120 {
 121         EVSIGBASE_LOCK();
 122         evsig_base = base;
 123         evsig_base_n_signals_added = base->sig.ev_n_signals_added;
 124         evsig_base_fd = base->sig.ev_signal_pair[0];
 125         EVSIGBASE_UNLOCK();
 126 }
 127 
 128 /* Callback for when the signal handler write a byte to our signaling socket */
 129 static void
 130 evsig_cb(evutil_socket_t fd, short what, void *arg)
 131 {
 132         static char signals[1024];
 133         ev_ssize_t n;
 134         int i;
 135         int ncaught[NSIG];
 136         struct event_base *base;
 137 
 138         base = arg;
 139 
 140         memset(&ncaught, 0, sizeof(ncaught));
 141 
 142         while (1) {
 143                 n = recv(fd, signals, sizeof(signals), 0);
 144                 if (n == -1) {
 145                         int err = evutil_socket_geterror(fd);
 146                         if (! EVUTIL_ERR_RW_RETRIABLE(err))
 147                                 event_sock_err(1, fd, "%s: recv", __func__);
 148                         break;
 149                 } else if (n == 0) {
 150                         /* XXX warn? */
 151                         break;
 152                 }
 153                 for (i = 0; i < n; ++i) {
 154                         ev_uint8_t sig = signals[i];
 155                         if (sig < NSIG)
 156                                 ncaught[sig]++;
 157                 }
 158         }
 159 
 160         EVBASE_ACQUIRE_LOCK(base, th_base_lock);
 161         for (i = 0; i < NSIG; ++i) {
 162                 if (ncaught[i])
 163                         evmap_signal_active(base, i, ncaught[i]);
 164         }
 165         EVBASE_RELEASE_LOCK(base, th_base_lock);
 166 }
 167 
 168 int
 169 evsig_init(struct event_base *base)
 170 {
 171         /*
 172          * Our signal handler is going to write to one end of the socket
 173          * pair to wake up our event loop.  The event loop then scans for
 174          * signals that got delivered.
 175          */
 176         if (evutil_socketpair(
 177                     AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
 178 #ifdef WIN32
 179                 /* Make this nonfatal on win32, where sometimes people
 180                    have localhost firewalled. */
 181                 event_sock_warn(-1, "%s: socketpair", __func__);
 182 #else
 183                 event_sock_err(1, -1, "%s: socketpair", __func__);
 184 #endif
 185                 return -1;
 186         }
 187 
 188         evutil_make_socket_closeonexec(base->sig.ev_signal_pair[0]);
 189         evutil_make_socket_closeonexec(base->sig.ev_signal_pair[1]);
 190         base->sig.sh_old = NULL;
 191         base->sig.sh_old_max = 0;
 192 
 193         evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
 194         evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
 195 
 196         event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[1],
 197                 EV_READ | EV_PERSIST, evsig_cb, base);
 198 
 199         base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
 200         event_priority_set(&base->sig.ev_signal, 0);
 201 
 202         base->evsigsel = &evsigops;
 203 
 204         return 0;
 205 }
 206 
 207 /* Helper: set the signal handler for evsignal to handler in base, so that
 208  * we can restore the original handler when we clear the current one. */
 209 int
 210 _evsig_set_handler(struct event_base *base,
 211     int evsignal, void (__cdecl *handler)(int))
 212 {
 213 #ifdef _EVENT_HAVE_SIGACTION
 214         struct sigaction sa;
 215 #else
 216         ev_sighandler_t sh;
 217 #endif
 218         struct evsig_info *sig = &base->sig;
 219         void *p;
 220 
 221         /*
 222          * resize saved signal handler array up to the highest signal number.
 223          * a dynamic array is used to keep footprint on the low side.
 224          */
 225         if (evsignal >= sig->sh_old_max) {
 226                 int new_max = evsignal + 1;
 227                 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
 228                             __func__, evsignal, sig->sh_old_max));
 229                 p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
 230                 if (p == NULL) {
 231                         event_warn("realloc");
 232                         return (-1);
 233                 }
 234 
 235                 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
 236                     0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
 237 
 238                 sig->sh_old_max = new_max;
 239                 sig->sh_old = p;
 240         }
 241 
 242         /* allocate space for previous handler out of dynamic array */
 243         sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
 244         if (sig->sh_old[evsignal] == NULL) {
 245                 event_warn("malloc");
 246                 return (-1);
 247         }
 248 
 249         /* save previous handler and setup new handler */
 250 #ifdef _EVENT_HAVE_SIGACTION
 251         memset(&sa, 0, sizeof(sa));
 252         sa.sa_handler = handler;
 253         sa.sa_flags |= SA_RESTART;
 254         sigfillset(&sa.sa_mask);
 255 
 256         if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
 257                 event_warn("sigaction");
 258                 mm_free(sig->sh_old[evsignal]);
 259                 sig->sh_old[evsignal] = NULL;
 260                 return (-1);
 261         }
 262 #else
 263         if ((sh = signal(evsignal, handler)) == SIG_ERR) {
 264                 event_warn("signal");
 265                 mm_free(sig->sh_old[evsignal]);
 266                 sig->sh_old[evsignal] = NULL;
 267                 return (-1);
 268         }
 269         *sig->sh_old[evsignal] = sh;
 270 #endif
 271 
 272         return (0);
 273 }
 274 
 275 static int
 276 evsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
 277 {
 278         struct evsig_info *sig = &base->sig;
 279         (void)p;
 280 
 281         EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
 282 
 283         /* catch signals if they happen quickly */
 284         EVSIGBASE_LOCK();
 285         if (evsig_base != base && evsig_base_n_signals_added) {
 286                 event_warnx("Added a signal to event base %p with signals "
 287                     "already added to event_base %p.  Only one can have "
 288                     "signals at a time with the %s backend.  The base with "
 289                     "the most recently added signal or the most recent "
 290                     "event_base_loop() call gets preference; do "
 291                     "not rely on this behavior in future Libevent versions.",
 292                     base, evsig_base, base->evsel->name);
 293         }
 294         evsig_base = base;
 295         evsig_base_n_signals_added = ++sig->ev_n_signals_added;
 296         evsig_base_fd = base->sig.ev_signal_pair[0];
 297         EVSIGBASE_UNLOCK();
 298 
 299         event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
 300         if (_evsig_set_handler(base, (int)evsignal, evsig_handler) == -1) {
 301                 goto err;
 302         }
 303 
 304 
 305         if (!sig->ev_signal_added) {
 306                 if (event_add(&sig->ev_signal, NULL))
 307                         goto err;
 308                 sig->ev_signal_added = 1;
 309         }
 310 
 311         return (0);
 312 
 313 err:
 314         EVSIGBASE_LOCK();
 315         --evsig_base_n_signals_added;
 316         --sig->ev_n_signals_added;
 317         EVSIGBASE_UNLOCK();
 318         return (-1);
 319 }
 320 
 321 int
 322 _evsig_restore_handler(struct event_base *base, int evsignal)
 323 {
 324         int ret = 0;
 325         struct evsig_info *sig = &base->sig;
 326 #ifdef _EVENT_HAVE_SIGACTION
 327         struct sigaction *sh;
 328 #else
 329         ev_sighandler_t *sh;
 330 #endif
 331 
 332         /* restore previous handler */
 333         sh = sig->sh_old[evsignal];
 334         sig->sh_old[evsignal] = NULL;
 335 #ifdef _EVENT_HAVE_SIGACTION
 336         if (sigaction(evsignal, sh, NULL) == -1) {
 337                 event_warn("sigaction");
 338                 ret = -1;
 339         }
 340 #else
 341         if (signal(evsignal, *sh) == SIG_ERR) {
 342                 event_warn("signal");
 343                 ret = -1;
 344         }
 345 #endif
 346 
 347         mm_free(sh);
 348 
 349         return ret;
 350 }
 351 
 352 static int
 353 evsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
 354 {
 355         EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
 356 
 357         event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
 358                 __func__, EV_SOCK_ARG(evsignal)));
 359 
 360         EVSIGBASE_LOCK();
 361         --evsig_base_n_signals_added;
 362         --base->sig.ev_n_signals_added;
 363         EVSIGBASE_UNLOCK();
 364 
 365         return (_evsig_restore_handler(base, (int)evsignal));
 366 }
 367 
 368 static void __cdecl
 369 evsig_handler(int sig)
 370 {
 371         int save_errno = errno;
 372 #ifdef WIN32
 373         int socket_errno = EVUTIL_SOCKET_ERROR();
 374 #endif
 375         ev_uint8_t msg;
 376 
 377         if (evsig_base == NULL) {
 378                 event_warnx(
 379                         "%s: received signal %d, but have no base configured",
 380                         __func__, sig);
 381                 return;
 382         }
 383 
 384 #ifndef _EVENT_HAVE_SIGACTION
 385         signal(sig, evsig_handler);
 386 #endif
 387 
 388         /* Wake up our notification mechanism */
 389         msg = sig;
 390         send(evsig_base_fd, (char*)&msg, 1, 0);
 391         errno = save_errno;
 392 #ifdef WIN32
 393         EVUTIL_SET_SOCKET_ERROR(socket_errno);
 394 #endif
 395 }
 396 
 397 void
 398 evsig_dealloc(struct event_base *base)
 399 {
 400         int i = 0;
 401         if (base->sig.ev_signal_added) {
 402                 event_del(&base->sig.ev_signal);
 403                 base->sig.ev_signal_added = 0;
 404         }
 405         /* debug event is created in evsig_init/event_assign even when
 406          * ev_signal_added == 0, so unassign is required */
 407         event_debug_unassign(&base->sig.ev_signal);
 408 
 409         for (i = 0; i < NSIG; ++i) {
 410                 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
 411                         _evsig_restore_handler(base, i);
 412         }
 413         EVSIGBASE_LOCK();
 414         if (base == evsig_base) {
 415                 evsig_base = NULL;
 416                 evsig_base_n_signals_added = 0;
 417                 evsig_base_fd = -1;
 418         }
 419         EVSIGBASE_UNLOCK();
 420 
 421         if (base->sig.ev_signal_pair[0] != -1) {
 422                 evutil_closesocket(base->sig.ev_signal_pair[0]);
 423                 base->sig.ev_signal_pair[0] = -1;
 424         }
 425         if (base->sig.ev_signal_pair[1] != -1) {
 426                 evutil_closesocket(base->sig.ev_signal_pair[1]);
 427                 base->sig.ev_signal_pair[1] = -1;
 428         }
 429         base->sig.sh_old_max = 0;
 430 
 431         /* per index frees are handled in evsig_del() */
 432         if (base->sig.sh_old) {
 433                 mm_free(base->sig.sh_old);
 434                 base->sig.sh_old = NULL;
 435         }
 436 }
 437 
 438 #ifndef _EVENT_DISABLE_THREAD_SUPPORT
 439 int
 440 evsig_global_setup_locks_(const int enable_locks)
 441 {
 442         EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
 443         return 0;
 444 }
 445 #endif

/* [<][>][^][v][top][bottom][index][help] */