Mercurial > octave
changeset 31792:30b6a8be7128 stable
attempt to avoid race condition when initializing list of async signals
* cxx-signal-helpers.cc: New file. Move
(async_signals): New file-scope static const variable.
(octave_block_async_signals, octave_unblock_async_signals,
signal_watcher, octave_create_interrupt_watcher_thread):
Move functions here from signal-wrappers.c. Use file-scope
async_signals variable instead of calling octave_async_signals to get
list of asynchronous signals.
(init_async_signals): Rename from octave_async_signals and move here
from signal-wrappers.cc. Return sigset_t object instead of pointer to
static storage that is local to the function.
* module.mk: Update.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 08 Dec 2022 13:57:18 -0500 |
parents | abe72b9464d6 |
children | 0aa88d03fa50 17d568574e1c |
files | liboctave/wrappers/cxx-signal-helpers.cc liboctave/wrappers/module.mk liboctave/wrappers/signal-wrappers.c liboctave/wrappers/signal-wrappers.h |
diffstat | 4 files changed, 218 insertions(+), 150 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/wrappers/cxx-signal-helpers.cc Thu Dec 08 13:57:18 2022 -0500 @@ -0,0 +1,209 @@ +//////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016-2022 The Octave Project Developers +// +// See the file COPYRIGHT.md in the top-level directory of this +// distribution or <https://octave.org/copyright/>. +// +// This file is part of Octave. +// +// Octave is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Octave is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Octave; see the file COPYING. If not, see +// <https://www.gnu.org/licenses/>. +// +//////////////////////////////////////////////////////////////////////// + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include <sys/types.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> + +#if defined (__WIN32__) && ! defined (__CYGWIN__) +# include <windows.h> +#else +# include <pthread.h> +#endif + +#include "signal-wrappers.h" + +#if ! defined (__WIN32__) || defined (__CYGWIN__) + +// The following pattern often used in C code to initialize a static +// variable could possibly cause trouble in multi-threaded code: +// +// TYPE * get_var (void) { +// static bool initialized = false; +// static TYPE *var; +// if (! initialized) { +// var = ...; +// initialized = true; +// } +// return var; +// } +// +// Changing this code to +// +// static TYPE *var = init_var (void); +// +// doesn't work in C because the static variable can't be initialized by +// a function call. So we have to do this job in C++. To avoid calling +// new, initialize sigset_t rather than a pointer to allocated storage. + +static const sigset_t +init_async_signals (void) +{ + sigset_t sigmask; + + sigemptyset (&sigmask); + + // The signals listed here should match the list of signals that + // we handle in the signal handler thread. + + // Interrupt signals. + +#if defined (SIGINT) + sigaddset (&sigmask, SIGINT); +#endif + +#if defined (SIGBREAK) + sigaddset (&sigmask, SIGBREAK); +#endif + + // Termination signals. + +#if defined (SIGHUP) + sigaddset (&sigmask, SIGHUP); +#endif + +#if defined (SIGQUIT) + sigaddset (&sigmask, SIGQUIT); +#endif + +#if defined (SIGTERM) + sigaddset (&sigmask, SIGTERM); +#endif + + // Alarm signals. + +#if defined (SIGALRM) + sigaddset (&sigmask, SIGALRM); +#endif + +#if defined (SIGVTALRM) + sigaddset (&sigmask, SIGVTALRM); +#endif + + // I/O signals. + +#if defined (SIGLOST) + sigaddset (&sigmask, SIGLOST); +#endif + +#if defined (SIGPIPE) + sigaddset (&sigmask, SIGPIPE); +#endif + + // Job control signals. + +#if defined (SIGCHLD) + sigaddset (&sigmask, SIGCHLD); +#endif + +#if defined (SIGCLD) + sigaddset (&sigmask, SIGCLD); +#endif + + // Resource limit signals. + +#if defined (SIGXCPU) + sigaddset (&sigmask, SIGXCPU); +#endif + +#if defined (SIGXFSZ) + sigaddset (&sigmask, SIGXFSZ); +#endif + + return sigmask; +} + +// Initialized once, is const so we never write to it again and it can +// be accessed by multiple threads without locking. + +static const sigset_t async_signals = init_async_signals (); + +#endif + +void +octave_block_async_signals (void) +{ +#if ! defined (__WIN32__) || defined (__CYGWIN__) + pthread_sigmask (SIG_BLOCK, &async_signals, 0); +#endif +} + +void +octave_unblock_async_signals (void) +{ +#if ! defined (__WIN32__) || defined (__CYGWIN__) + pthread_sigmask (SIG_UNBLOCK, &async_signals, 0); +#endif +} + +#if ! defined (__WIN32__) || defined (__CYGWIN__) + +static void * +signal_watcher (void *arg) +{ + octave_sig_handler *handler = reinterpret_cast<octave_sig_handler *> (arg); + + octave_unblock_async_signals (); + + while (1) + { + int sig_caught; + + if (sigwait (&async_signals, &sig_caught)) + { + // FIXME: what else should we do? + abort (); + } + + // Let handler have complete control over what to do. + (*handler) (sig_caught); + } +} + +#endif + +void +octave_create_interrupt_watcher_thread (octave_sig_handler *handler) +{ +#if ! defined (__WIN32__) + pthread_t sighandler_thread_id; + + if (pthread_create (&sighandler_thread_id, 0, signal_watcher, + reinterpret_cast<void *> (handler))) + { + // FIXME: what else should we do? + abort (); + } +#else + octave_unblock_async_signals (); + + octave_unused_parameter (handler); +#endif +}
--- a/liboctave/wrappers/module.mk Sun Jan 29 13:03:23 2023 -0500 +++ b/liboctave/wrappers/module.mk Thu Dec 08 13:57:18 2022 -0500 @@ -46,6 +46,7 @@ %reldir%/async-system-wrapper.c \ %reldir%/base64-wrappers.c \ %reldir%/canonicalize-file-name-wrapper.c \ + %reldir%/cxx-signal-helpers.cc \ %reldir%/dirent-wrappers.c \ %reldir%/fcntl-wrappers.c \ %reldir%/filepos-wrappers.c \
--- a/liboctave/wrappers/signal-wrappers.c Sun Jan 29 13:03:23 2023 -0500 +++ b/liboctave/wrappers/signal-wrappers.c Thu Dec 08 13:57:18 2022 -0500 @@ -576,107 +576,6 @@ sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0); } -#if ! defined (__WIN32__) -static const sigset_t * -octave_async_signals (void) -{ - static bool initialized = false; - static sigset_t sigmask; - - if (! initialized) - { - sigemptyset (&sigmask); - - // The signals listed here should match the list of signals that - // we handle in the signal handler thread. - - // Interrupt signals. - -#if defined (SIGINT) - sigaddset (&sigmask, SIGINT); -#endif - -#if defined (SIGBREAK) - sigaddset (&sigmask, SIGBREAK); -#endif - - // Termination signals. - -#if defined (SIGHUP) - sigaddset (&sigmask, SIGHUP); -#endif - -#if defined (SIGQUIT) - sigaddset (&sigmask, SIGQUIT); -#endif - -#if defined (SIGTERM) - sigaddset (&sigmask, SIGTERM); -#endif - - // Alarm signals. - -#if defined (SIGALRM) - sigaddset (&sigmask, SIGALRM); -#endif - -#if defined (SIGVTALRM) - sigaddset (&sigmask, SIGVTALRM); -#endif - - // I/O signals. - -#if defined (SIGLOST) - sigaddset (&sigmask, SIGLOST); -#endif - -#if defined (SIGPIPE) - sigaddset (&sigmask, SIGPIPE); -#endif - - // Job control signals. - -#if defined (SIGCHLD) - sigaddset (&sigmask, SIGCHLD); -#endif - -#if defined (SIGCLD) - sigaddset (&sigmask, SIGCLD); -#endif - - // Resource limit signals. - -#if defined (SIGXCPU) - sigaddset (&sigmask, SIGXCPU); -#endif - -#if defined (SIGXFSZ) - sigaddset (&sigmask, SIGXFSZ); -#endif - - initialized = true; - } - - return &sigmask; -} -#endif - -void -octave_block_async_signals (void) -{ -#if ! defined (__WIN32__) || defined (__CYGWIN__) - pthread_sigmask (SIG_BLOCK, octave_async_signals (), 0); -#endif -} - -void -octave_unblock_async_signals (void) -{ -#if ! defined (__WIN32__) || defined (__CYGWIN__) - pthread_sigmask (SIG_UNBLOCK, octave_async_signals (), 0); -#endif -} - int octave_raise_wrapper (int signum) { @@ -684,50 +583,6 @@ } #if ! defined (__WIN32__) -static void * -signal_watcher (void *arg) -{ - octave_sig_handler *handler = (octave_sig_handler *) arg; - - octave_unblock_async_signals (); - - const sigset_t *async_signals = octave_async_signals (); - - while (1) - { - int sig_caught; - - if (sigwait (async_signals, &sig_caught)) - { - // FIXME: what else should we do? - abort (); - } - - // Let handler have complete control over what to do. - (*handler) (sig_caught); - } -} -#endif - -void -octave_create_interrupt_watcher_thread (octave_sig_handler *handler) -{ -#if ! defined (__WIN32__) - pthread_t sighandler_thread_id; - - if (pthread_create (&sighandler_thread_id, 0, signal_watcher, handler)) - { - // FIXME: what else should we do? - abort (); - } -#else - octave_unblock_async_signals (); - - octave_unused_parameter (handler); -#endif -} - -#if ! defined (__WIN32__) static void print_sigset (FILE *of, const char *prefix, const sigset_t *sigset) {
--- a/liboctave/wrappers/signal-wrappers.h Sun Jan 29 13:03:23 2023 -0500 +++ b/liboctave/wrappers/signal-wrappers.h Thu Dec 08 13:57:18 2022 -0500 @@ -87,17 +87,20 @@ extern OCTAVE_API void octave_set_signal_mask (void *mask); -extern OCTAVE_API void octave_block_async_signals (void); +extern OCTAVE_API int octave_raise_wrapper (int signum); + +// This function can be useful for debugging. -extern OCTAVE_API void octave_unblock_async_signals (void); +extern OCTAVE_API void octave_show_sigmask (const char *); -extern OCTAVE_API int octave_raise_wrapper (int signum); +// The next three functions are defined in cxx-signal-helpers.cc. extern OCTAVE_API void octave_create_interrupt_watcher_thread (octave_sig_handler *handler); -// This can be useful for debugging. -extern OCTAVE_API void octave_show_sigmask (const char *); +extern OCTAVE_API void octave_block_async_signals (void); + +extern OCTAVE_API void octave_unblock_async_signals (void); #if defined __cplusplus }