LCOV - code coverage report
Current view: top level - lib - fatal-signal.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 99 113 87.6 %
Date: 2016-09-14 01:02:56 Functions: 16 17 94.1 %
Branches: 34 44 77.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : #include <config.h>
      17                 :            : #include "fatal-signal.h"
      18                 :            : #include <errno.h>
      19                 :            : #include <signal.h>
      20                 :            : #include <stdbool.h>
      21                 :            : #include <stdio.h>
      22                 :            : #include <stdint.h>
      23                 :            : #include <stdlib.h>
      24                 :            : #include <string.h>
      25                 :            : #include <unistd.h>
      26                 :            : #include "ovs-thread.h"
      27                 :            : #include "poll-loop.h"
      28                 :            : #include "openvswitch/shash.h"
      29                 :            : #include "sset.h"
      30                 :            : #include "signals.h"
      31                 :            : #include "socket-util.h"
      32                 :            : #include "util.h"
      33                 :            : #include "openvswitch/vlog.h"
      34                 :            : 
      35                 :            : #include "openvswitch/type-props.h"
      36                 :            : 
      37                 :            : #ifndef SIG_ATOMIC_MAX
      38                 :            : #define SIG_ATOMIC_MAX TYPE_MAXIMUM(sig_atomic_t)
      39                 :            : #endif
      40                 :            : 
      41                 :      53956 : VLOG_DEFINE_THIS_MODULE(fatal_signal);
      42                 :            : 
      43                 :            : /* Signals to catch. */
      44                 :            : #ifndef _WIN32
      45                 :            : static const int fatal_signals[] = { SIGTERM, SIGINT, SIGHUP, SIGALRM };
      46                 :            : #else
      47                 :            : static const int fatal_signals[] = { SIGTERM };
      48                 :            : #endif
      49                 :            : 
      50                 :            : /* Hooks to call upon catching a signal */
      51                 :            : struct hook {
      52                 :            :     void (*hook_cb)(void *aux);
      53                 :            :     void (*cancel_cb)(void *aux);
      54                 :            :     void *aux;
      55                 :            :     bool run_at_exit;
      56                 :            : };
      57                 :            : #define MAX_HOOKS 32
      58                 :            : static struct hook hooks[MAX_HOOKS];
      59                 :            : static size_t n_hooks;
      60                 :            : 
      61                 :            : static int signal_fds[2];
      62                 :            : static volatile sig_atomic_t stored_sig_nr = SIG_ATOMIC_MAX;
      63                 :            : 
      64                 :            : #ifdef _WIN32
      65                 :            : static HANDLE wevent;
      66                 :            : #endif
      67                 :            : 
      68                 :            : static struct ovs_mutex mutex;
      69                 :            : 
      70                 :            : static void call_hooks(int sig_nr);
      71                 :            : #ifdef _WIN32
      72                 :            : static BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType);
      73                 :            : #endif
      74                 :            : 
      75                 :            : /* Initializes the fatal signal handling module.  Calling this function is
      76                 :            :  * optional, because calling any other function in the module will also
      77                 :            :  * initialize it.  However, in a multithreaded program, the module must be
      78                 :            :  * initialized while the process is still single-threaded. */
      79                 :            : void
      80                 :     815238 : fatal_signal_init(void)
      81                 :            : {
      82                 :            :     static bool inited = false;
      83                 :            : 
      84         [ +  + ]:     815238 :     if (!inited) {
      85                 :            :         size_t i;
      86                 :            : 
      87                 :      23626 :         assert_single_threaded();
      88                 :      23626 :         inited = true;
      89                 :            : 
      90                 :      23626 :         ovs_mutex_init_recursive(&mutex);
      91                 :            : #ifndef _WIN32
      92                 :      23626 :         xpipe_nonblocking(signal_fds);
      93                 :            : #else
      94                 :            :         wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
      95                 :            :         if (!wevent) {
      96                 :            :             char *msg_buf = ovs_lasterror_to_string();
      97                 :            :             VLOG_FATAL("Failed to create a event (%s).", msg_buf);
      98                 :            :         }
      99                 :            : 
     100                 :            :         /* Register a function to handle Ctrl+C. */
     101                 :            :         SetConsoleCtrlHandler(ConsoleHandlerRoutine, true);
     102                 :            : #endif
     103                 :            : 
     104         [ +  + ]:     118130 :         for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
     105                 :      94504 :             int sig_nr = fatal_signals[i];
     106                 :            : #ifndef _WIN32
     107                 :            :             struct sigaction old_sa;
     108                 :            : 
     109                 :      94504 :             xsigaction(sig_nr, NULL, &old_sa);
     110         [ +  + ]:      94504 :             if (old_sa.sa_handler == SIG_DFL
     111         [ -  + ]:      94501 :                 && signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
     112                 :          0 :                 VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
     113                 :            :             }
     114                 :            : #else
     115                 :            :             if (signal(sig_nr, fatal_signal_handler) == SIG_ERR) {
     116                 :            :                 VLOG_FATAL("signal failed (%s)", ovs_strerror(errno));
     117                 :            :             }
     118                 :            : #endif
     119                 :            :         }
     120                 :      23626 :         atexit(fatal_signal_atexit_handler);
     121                 :            :     }
     122                 :     815238 : }
     123                 :            : 
     124                 :            : /* Registers 'hook_cb' to be called from inside poll_block() following a fatal
     125                 :            :  * signal.  'hook_cb' does not need to be async-signal-safe.  In a
     126                 :            :  * multithreaded program 'hook_cb' might be called from any thread, with
     127                 :            :  * threads other than the one running 'hook_cb' in unknown states.
     128                 :            :  *
     129                 :            :  * If 'run_at_exit' is true, 'hook_cb' is also called during normal process
     130                 :            :  * termination, e.g. when exit() is called or when main() returns.
     131                 :            :  *
     132                 :            :  * If the current process forks, fatal_signal_fork() may be called to clear the
     133                 :            :  * parent process's fatal signal hooks, so that 'hook_cb' is only called when
     134                 :            :  * the child terminates, not when the parent does.  When fatal_signal_fork() is
     135                 :            :  * called, it calls the 'cancel_cb' function if it is nonnull, passing 'aux',
     136                 :            :  * to notify that the hook has been canceled.  This allows the hook to free
     137                 :            :  * memory, etc. */
     138                 :            : void
     139                 :      19354 : fatal_signal_add_hook(void (*hook_cb)(void *aux), void (*cancel_cb)(void *aux),
     140                 :            :                       void *aux, bool run_at_exit)
     141                 :            : {
     142                 :      19354 :     fatal_signal_init();
     143                 :            : 
     144                 :      19354 :     ovs_mutex_lock(&mutex);
     145         [ -  + ]:      19354 :     ovs_assert(n_hooks < MAX_HOOKS);
     146                 :      19354 :     hooks[n_hooks].hook_cb = hook_cb;
     147                 :      19354 :     hooks[n_hooks].cancel_cb = cancel_cb;
     148                 :      19354 :     hooks[n_hooks].aux = aux;
     149                 :      19354 :     hooks[n_hooks].run_at_exit = run_at_exit;
     150                 :      19354 :     n_hooks++;
     151                 :      19354 :     ovs_mutex_unlock(&mutex);
     152                 :      19354 : }
     153                 :            : 
     154                 :            : /* Handles fatal signal number 'sig_nr'.
     155                 :            :  *
     156                 :            :  * Ordinarily this is the actual signal handler.  When other code needs to
     157                 :            :  * handle one of our signals, however, it can register for that signal and, if
     158                 :            :  * and when necessary, call this function to do fatal signal processing for it
     159                 :            :  * and terminate the process.  Currently only timeval.c does this, for SIGALRM.
     160                 :            :  * (It is not important whether the other code sets up its signal handler
     161                 :            :  * before or after this file, because this file will only set up a signal
     162                 :            :  * handler in the case where the signal has its default handling.)  */
     163                 :            : void
     164                 :          0 : fatal_signal_handler(int sig_nr)
     165                 :            : {
     166                 :            : #ifndef _WIN32
     167                 :          0 :     ignore(write(signal_fds[1], "", 1));
     168                 :            : #else
     169                 :            :     SetEvent(wevent);
     170                 :            : #endif
     171                 :          0 :     stored_sig_nr = sig_nr;
     172                 :          0 : }
     173                 :            : 
     174                 :            : /* Check whether a fatal signal has occurred and, if so, call the fatal signal
     175                 :            :  * hooks and exit.
     176                 :            :  *
     177                 :            :  * This function is called automatically by poll_block(), but specialized
     178                 :            :  * programs that may not always call poll_block() on a regular basis should
     179                 :            :  * also call it periodically.  (Therefore, any function with "block" in its
     180                 :            :  * name should call fatal_signal_run() each time it is called, either directly
     181                 :            :  * or through poll_block(), because such functions can only used by specialized
     182                 :            :  * programs that can afford to block outside their main loop around
     183                 :            :  * poll_block().)
     184                 :            :  */
     185                 :            : void
     186                 :     430363 : fatal_signal_run(void)
     187                 :            : {
     188                 :            :     sig_atomic_t sig_nr;
     189                 :            : 
     190                 :     430363 :     fatal_signal_init();
     191                 :            : 
     192                 :     430361 :     sig_nr = stored_sig_nr;
     193         [ -  + ]:     430361 :     if (sig_nr != SIG_ATOMIC_MAX) {
     194                 :            :         char namebuf[SIGNAL_NAME_BUFSIZE];
     195                 :            : 
     196                 :          0 :         ovs_mutex_lock(&mutex);
     197                 :            : 
     198                 :            : #ifndef _WIN32
     199         [ #  # ]:          0 :         VLOG_WARN("terminating with signal %d (%s)",
     200                 :            :                   (int)sig_nr, signal_name(sig_nr, namebuf, sizeof namebuf));
     201                 :            : #else
     202                 :            :         VLOG_WARN("terminating with signal %d", (int)sig_nr);
     203                 :            : #endif
     204                 :          0 :         call_hooks(sig_nr);
     205                 :          0 :         fflush(stderr);
     206                 :            : 
     207                 :            :         /* Re-raise the signal with the default handling so that the program
     208                 :            :          * termination status reflects that we were killed by this signal */
     209                 :          0 :         signal(sig_nr, SIG_DFL);
     210                 :          0 :         raise(sig_nr);
     211                 :            : 
     212                 :          0 :         ovs_mutex_unlock(&mutex);
     213                 :          0 :         OVS_NOT_REACHED();
     214                 :            :     }
     215                 :     430361 : }
     216                 :            : 
     217                 :            : void
     218                 :     344803 : fatal_signal_wait(void)
     219                 :            : {
     220                 :     344803 :     fatal_signal_init();
     221                 :            : #ifdef _WIN32
     222                 :            :     poll_wevent_wait(wevent);
     223                 :            : #else
     224                 :     344802 :     poll_fd_wait(signal_fds[0], POLLIN);
     225                 :            : #endif
     226                 :     344803 : }
     227                 :            : 
     228                 :            : void
     229                 :      15097 : fatal_ignore_sigpipe(void)
     230                 :            : {
     231                 :            : #ifndef _WIN32
     232                 :      15097 :     signal(SIGPIPE, SIG_IGN);
     233                 :            : #endif
     234                 :      15097 : }
     235                 :            : 
     236                 :            : void
     237                 :      24341 : fatal_signal_atexit_handler(void)
     238                 :            : {
     239                 :      24341 :     call_hooks(0);
     240                 :      24341 : }
     241                 :            : 
     242                 :            : static void
     243                 :      24341 : call_hooks(int sig_nr)
     244                 :            : {
     245                 :            :     static volatile sig_atomic_t recurse = 0;
     246         [ +  - ]:      24341 :     if (!recurse) {
     247                 :            :         size_t i;
     248                 :            : 
     249                 :      24341 :         recurse = 1;
     250                 :            : 
     251         [ +  + ]:      43667 :         for (i = 0; i < n_hooks; i++) {
     252                 :      19326 :             struct hook *h = &hooks[i];
     253 [ +  - ][ +  - ]:      19326 :             if (sig_nr || h->run_at_exit) {
     254                 :      19326 :                 h->hook_cb(h->aux);
     255                 :            :             }
     256                 :            :         }
     257                 :            :     }
     258                 :      24341 : }
     259                 :            : 
     260                 :            : #ifdef _WIN32
     261                 :            : BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
     262                 :            : {
     263                 :            :     stored_sig_nr = SIGINT;
     264                 :            :     SetEvent(wevent);
     265                 :            :     return true;
     266                 :            : }
     267                 :            : #endif
     268                 :            : 
     269                 :            : /* Files to delete on exit. */
     270                 :            : static struct sset files = SSET_INITIALIZER(&files);
     271                 :            : 
     272                 :            : /* Has a hook function been registered with fatal_signal_add_hook() (and not
     273                 :            :  * cleared by fatal_signal_fork())? */
     274                 :            : static bool added_hook;
     275                 :            : 
     276                 :            : static void unlink_files(void *aux);
     277                 :            : static void cancel_files(void *aux);
     278                 :            : static void do_unlink_files(void);
     279                 :            : 
     280                 :            : /* Registers 'file' to be unlinked when the program terminates via exit() or a
     281                 :            :  * fatal signal. */
     282                 :            : void
     283                 :       9050 : fatal_signal_add_file_to_unlink(const char *file)
     284                 :            : {
     285                 :       9050 :     fatal_signal_init();
     286                 :            : 
     287                 :       9050 :     ovs_mutex_lock(&mutex);
     288         [ +  + ]:       9050 :     if (!added_hook) {
     289                 :       2191 :         added_hook = true;
     290                 :       2191 :         fatal_signal_add_hook(unlink_files, cancel_files, NULL, true);
     291                 :            :     }
     292                 :            : 
     293                 :       9050 :     sset_add(&files, file);
     294                 :       9050 :     ovs_mutex_unlock(&mutex);
     295                 :       9050 : }
     296                 :            : 
     297                 :            : /* Unregisters 'file' from being unlinked when the program terminates via
     298                 :            :  * exit() or a fatal signal. */
     299                 :            : void
     300                 :       6868 : fatal_signal_remove_file_to_unlink(const char *file)
     301                 :            : {
     302                 :       6868 :     fatal_signal_init();
     303                 :            : 
     304                 :       6868 :     ovs_mutex_lock(&mutex);
     305                 :       6868 :     sset_find_and_delete(&files, file);
     306                 :       6868 :     ovs_mutex_unlock(&mutex);
     307                 :       6868 : }
     308                 :            : 
     309                 :            : /* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'.
     310                 :            :  * Returns 0 if successful, otherwise a positive errno value. */
     311                 :            : int
     312                 :       4801 : fatal_signal_unlink_file_now(const char *file)
     313                 :            : {
     314                 :            :     int error;
     315                 :            : 
     316                 :       4801 :     fatal_signal_init();
     317                 :            : 
     318                 :       4801 :     ovs_mutex_lock(&mutex);
     319                 :            : 
     320         [ +  + ]:       4801 :     error = unlink(file) ? errno : 0;
     321         [ +  + ]:       4801 :     if (error) {
     322         [ +  - ]:          2 :         VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error));
     323                 :            :     }
     324                 :            : 
     325                 :       4801 :     fatal_signal_remove_file_to_unlink(file);
     326                 :            : 
     327                 :       4801 :     ovs_mutex_unlock(&mutex);
     328                 :            : 
     329                 :       4801 :     return error;
     330                 :            : }
     331                 :            : 
     332                 :            : static void
     333                 :       2189 : unlink_files(void *aux OVS_UNUSED)
     334                 :            : {
     335                 :       2189 :     do_unlink_files();
     336                 :       2189 : }
     337                 :            : 
     338                 :            : static void
     339                 :        111 : cancel_files(void *aux OVS_UNUSED)
     340                 :            : {
     341                 :        111 :     sset_clear(&files);
     342                 :        111 :     added_hook = false;
     343                 :        111 : }
     344                 :            : 
     345                 :            : static void
     346                 :       2189 : do_unlink_files(void)
     347                 :            : {
     348                 :            :     const char *file;
     349                 :            : 
     350 [ +  + ][ +  + ]:       4369 :     SSET_FOR_EACH (file, &files) {
                 [ +  + ]
     351                 :       2180 :         unlink(file);
     352                 :            :     }
     353                 :       2189 : }
     354                 :            : 
     355                 :            : /* Clears all of the fatal signal hooks without executing them.  If any of the
     356                 :            :  * hooks passed a 'cancel_cb' function to fatal_signal_add_hook(), then those
     357                 :            :  * functions will be called, allowing them to free resources, etc.
     358                 :            :  *
     359                 :            :  * Following a fork, one of the resulting processes can call this function to
     360                 :            :  * allow it to terminate without calling the hooks registered before calling
     361                 :            :  * this function.  New hooks registered after calling this function will take
     362                 :            :  * effect normally. */
     363                 :            : void
     364                 :       2257 : fatal_signal_fork(void)
     365                 :            : {
     366                 :            :     size_t i;
     367                 :            : 
     368                 :       2257 :     assert_single_threaded();
     369                 :            : 
     370         [ +  + ]:       3077 :     for (i = 0; i < n_hooks; i++) {
     371                 :        820 :         struct hook *h = &hooks[i];
     372         [ +  + ]:        820 :         if (h->cancel_cb) {
     373                 :        111 :             h->cancel_cb(h->aux);
     374                 :            :         }
     375                 :            :     }
     376                 :       2257 :     n_hooks = 0;
     377                 :            : 
     378                 :            :     /* Raise any signals that we have already received with the default
     379                 :            :      * handler. */
     380         [ -  + ]:       2257 :     if (stored_sig_nr != SIG_ATOMIC_MAX) {
     381                 :          0 :         raise(stored_sig_nr);
     382                 :            :     }
     383                 :       2257 : }
     384                 :            : 
     385                 :            : #ifndef _WIN32
     386                 :            : /* Blocks all fatal signals and returns previous signal mask into
     387                 :            :  * 'prev_mask'. */
     388                 :            : void
     389                 :        108 : fatal_signal_block(sigset_t *prev_mask)
     390                 :            : {
     391                 :            :     int i;
     392                 :            :     sigset_t block_mask;
     393                 :            : 
     394                 :        108 :     sigemptyset(&block_mask);
     395         [ +  + ]:        540 :     for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) {
     396                 :        432 :         int sig_nr = fatal_signals[i];
     397                 :        432 :         sigaddset(&block_mask, sig_nr);
     398                 :            :     }
     399                 :        108 :     xpthread_sigmask(SIG_BLOCK, &block_mask, prev_mask);
     400                 :        108 : }
     401                 :            : #endif

Generated by: LCOV version 1.12