diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:15 +0300 |
commit | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (patch) | |
tree | da2c34829458c7d4e74bdfbdf85dff449e9e7fb8 /library/cpp/sighandler/async_signals_handler.cpp | |
parent | 778e51ba091dc39e7b7fcab2b9cf4dbedfb6f2b5 (diff) | |
download | ydb-72cb13b4aff9bc9cf22e49251bc8fd143f82538f.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 1 of 2.
Diffstat (limited to 'library/cpp/sighandler/async_signals_handler.cpp')
-rw-r--r-- | library/cpp/sighandler/async_signals_handler.cpp | 314 |
1 files changed, 157 insertions, 157 deletions
diff --git a/library/cpp/sighandler/async_signals_handler.cpp b/library/cpp/sighandler/async_signals_handler.cpp index 00ce1c18fb..bf4a176ff3 100644 --- a/library/cpp/sighandler/async_signals_handler.cpp +++ b/library/cpp/sighandler/async_signals_handler.cpp @@ -1,5 +1,5 @@ #include "async_signals_handler.h" - + #include <util/system/platform.h> #if !defined(_win_) @@ -11,10 +11,10 @@ #include <unistd.h> -#if defined(_linux_) -#include <dlfcn.h> -#endif - +#if defined(_linux_) +#include <dlfcn.h> +#endif + #include <util/system/atomic.h> #include <util/system/defaults.h> #include <util/system/event.h> @@ -22,187 +22,187 @@ #include <util/system/spinlock.h> #include <util/system/thread.h> #include <util/system/yassert.h> -#include <util/generic/hash.h> +#include <util/generic/hash.h> -namespace { +namespace { volatile int SIGNAL_PIPE_WRITE_FD = 0; // will be initialized in ctor void WriteAllOrDie(const int fd, const void* buf, size_t bufsize) { - size_t totalBytesWritten = 0; - - while (totalBytesWritten != bufsize) { - const ssize_t result = write(fd, (const char*)buf + totalBytesWritten, bufsize - totalBytesWritten); - - Y_VERIFY(result >= 0 || (result == -1 && errno == EINTR), "write failed: %s (errno = %d)", strerror(errno), errno); - totalBytesWritten += static_cast<size_t>(result); - } + size_t totalBytesWritten = 0; + + while (totalBytesWritten != bufsize) { + const ssize_t result = write(fd, (const char*)buf + totalBytesWritten, bufsize - totalBytesWritten); + + Y_VERIFY(result >= 0 || (result == -1 && errno == EINTR), "write failed: %s (errno = %d)", strerror(errno), errno); + totalBytesWritten += static_cast<size_t>(result); + } } void PipeWriterSignalHandler(int, siginfo_t* info, void*) { - const ui8 signum = static_cast<ui8>(info->si_signo); - - WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &signum, 1); - } - - // Handler for the "asynchronous" unix signals (those which can occur - // at arbitrary point of execution and have no need to be reacted on instantly - // and/or to preserve execution context at the point of interrupt). - // - // Async signals -- SIGHUP, SIGUSR1 (used to cause configuration files reread for example) - // Sync signals -- fatal errors like SIGSEGV, SIGBUS... - class TAsyncSignalsHandler { - private: - TThread Thread; - int SignalPipeReadFd; - typedef TAutoPtr<TEventHandler> TEventHandlerPtr; - THashMap<int, TEventHandlerPtr> Handlers; - TRWMutex HandlersLock; - - TAtomic ShouldDie; + const ui8 signum = static_cast<ui8>(info->si_signo); + + WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &signum, 1); + } + + // Handler for the "asynchronous" unix signals (those which can occur + // at arbitrary point of execution and have no need to be reacted on instantly + // and/or to preserve execution context at the point of interrupt). + // + // Async signals -- SIGHUP, SIGUSR1 (used to cause configuration files reread for example) + // Sync signals -- fatal errors like SIGSEGV, SIGBUS... + class TAsyncSignalsHandler { + private: + TThread Thread; + int SignalPipeReadFd; + typedef TAutoPtr<TEventHandler> TEventHandlerPtr; + THashMap<int, TEventHandlerPtr> Handlers; + TRWMutex HandlersLock; + + TAtomic ShouldDie; TSystemEvent DieEvent; - static void* ThreadFunc(void* data) { - reinterpret_cast<TAsyncSignalsHandler*>(data)->RealThreadFunc(); - - return nullptr; + static void* ThreadFunc(void* data) { + reinterpret_cast<TAsyncSignalsHandler*>(data)->RealThreadFunc(); + + return nullptr; + } + + inline void RealThreadFunc() { + for (;;) { + ui8 signum; + const ssize_t bytesRead = read(SignalPipeReadFd, &signum, 1); + + Y_VERIFY(bytesRead >= 0 || (bytesRead == -1 && errno == EINTR), "read failed: %s (errno = %d)", strerror(errno), errno); + + if (AtomicAdd(ShouldDie, 0) != 0) { + DieEvent.Signal(); + + break; + } + + if (bytesRead == 0) { + break; + } else if (bytesRead == -1) { + continue; + } + + { + TReadGuard dnd(HandlersLock); + + const TEventHandlerPtr* handler = Handlers.FindPtr(signum); + Y_VERIFY(handler && handler->Get(), "Async signal handler is not set, it's a bug!"); + handler->Get()->Handle(signum); + } + } } - inline void RealThreadFunc() { - for (;;) { - ui8 signum; - const ssize_t bytesRead = read(SignalPipeReadFd, &signum, 1); - - Y_VERIFY(bytesRead >= 0 || (bytesRead == -1 && errno == EINTR), "read failed: %s (errno = %d)", strerror(errno), errno); - - if (AtomicAdd(ShouldDie, 0) != 0) { - DieEvent.Signal(); - - break; - } - - if (bytesRead == 0) { - break; - } else if (bytesRead == -1) { - continue; - } - - { - TReadGuard dnd(HandlersLock); - - const TEventHandlerPtr* handler = Handlers.FindPtr(signum); - Y_VERIFY(handler && handler->Get(), "Async signal handler is not set, it's a bug!"); - handler->Get()->Handle(signum); - } - } - } - - public: - TAsyncSignalsHandler() - : Thread(TThread::TParams(ThreadFunc, this).SetName("sighandler")) - , SignalPipeReadFd(0) - , ShouldDie(0) - { - int filedes[2] = {-1}; + public: + TAsyncSignalsHandler() + : Thread(TThread::TParams(ThreadFunc, this).SetName("sighandler")) + , SignalPipeReadFd(0) + , ShouldDie(0) + { + int filedes[2] = {-1}; #ifdef _linux_ - int result; - - { - using pipe2_t = decltype(pipe2); - pipe2_t* pipe2Ptr = (pipe2_t*)dlsym(RTLD_DEFAULT, "pipe2"); - -#if defined(_musl_) - if (!pipe2Ptr) { - pipe2Ptr = pipe2; - } + int result; + + { + using pipe2_t = decltype(pipe2); + pipe2_t* pipe2Ptr = (pipe2_t*)dlsym(RTLD_DEFAULT, "pipe2"); + +#if defined(_musl_) + if (!pipe2Ptr) { + pipe2Ptr = pipe2; + } +#endif + + if (pipe2Ptr) { + result = pipe2Ptr(filedes, O_CLOEXEC); + } else { + result = -1; + errno = ENOSYS; + } + } + + if (result != 0 && errno == ENOSYS) { // linux older than 2.6.27 returns "not implemented" #endif + Y_VERIFY(pipe(filedes) == 0, "pipe failed: %s (errno = %d)", strerror(errno), errno); - if (pipe2Ptr) { - result = pipe2Ptr(filedes, O_CLOEXEC); - } else { - result = -1; - errno = ENOSYS; - } - } - - if (result != 0 && errno == ENOSYS) { // linux older than 2.6.27 returns "not implemented" -#endif - Y_VERIFY(pipe(filedes) == 0, "pipe failed: %s (errno = %d)", strerror(errno), errno); - - SignalPipeReadFd = filedes[0]; - SIGNAL_PIPE_WRITE_FD = filedes[1]; - - Y_VERIFY(fcntl(SignalPipeReadFd, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno); - Y_VERIFY(fcntl(SIGNAL_PIPE_WRITE_FD, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno); + SignalPipeReadFd = filedes[0]; + SIGNAL_PIPE_WRITE_FD = filedes[1]; + + Y_VERIFY(fcntl(SignalPipeReadFd, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno); + Y_VERIFY(fcntl(SIGNAL_PIPE_WRITE_FD, F_SETFD, FD_CLOEXEC) == 0, "fcntl failed: %s (errno = %d)", strerror(errno), errno); #ifdef _linux_ - } else { - Y_VERIFY(result == 0, "pipe2 failed: %s (errno = %d)", strerror(errno), errno); - SignalPipeReadFd = filedes[0]; - SIGNAL_PIPE_WRITE_FD = filedes[1]; - } + } else { + Y_VERIFY(result == 0, "pipe2 failed: %s (errno = %d)", strerror(errno), errno); + SignalPipeReadFd = filedes[0]; + SIGNAL_PIPE_WRITE_FD = filedes[1]; + } #endif - Thread.Start(); - Thread.Detach(); - } + Thread.Start(); + Thread.Detach(); + } - ~TAsyncSignalsHandler() { - AtomicSwap(&ShouldDie, TAtomic(1)); - ui8 fakeSignal = 0; - WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &fakeSignal, 1); + ~TAsyncSignalsHandler() { + AtomicSwap(&ShouldDie, TAtomic(1)); + ui8 fakeSignal = 0; + WriteAllOrDie(SIGNAL_PIPE_WRITE_FD, &fakeSignal, 1); - DieEvent.WaitT(TDuration::Seconds(15)); + DieEvent.WaitT(TDuration::Seconds(15)); - /* may cause VERIFY failure in signal handler, propably we should leave it to process clean procedure + /* may cause VERIFY failure in signal handler, propably we should leave it to process clean procedure close(SIGNAL_PIPE_WRITE_FD); close(SignalPipeReadFd); */ + } + + bool DoInstall(int signum, TAutoPtr<TEventHandler> handler) { + TWriteGuard dnd(HandlersLock); + TEventHandlerPtr& ev = Handlers[signum]; + const bool ret = !ev; + + ev = handler; + + return ret; + } + + void Install(int signum, TAutoPtr<TEventHandler> handler) { + if (DoInstall(signum, handler)) { + struct sigaction a; + + memset(&a, 0, sizeof(a)); + a.sa_sigaction = PipeWriterSignalHandler; + a.sa_flags = SA_SIGINFO | SA_RESTART; + + Y_VERIFY(!sigaction(signum, &a, nullptr), "sigaction failed: %s (errno = %d)", strerror(errno), errno); + } } - - bool DoInstall(int signum, TAutoPtr<TEventHandler> handler) { - TWriteGuard dnd(HandlersLock); - TEventHandlerPtr& ev = Handlers[signum]; - const bool ret = !ev; - - ev = handler; - - return ret; - } - - void Install(int signum, TAutoPtr<TEventHandler> handler) { - if (DoInstall(signum, handler)) { - struct sigaction a; - - memset(&a, 0, sizeof(a)); - a.sa_sigaction = PipeWriterSignalHandler; - a.sa_flags = SA_SIGINFO | SA_RESTART; - - Y_VERIFY(!sigaction(signum, &a, nullptr), "sigaction failed: %s (errno = %d)", strerror(errno), errno); - } - } - }; - - // This pointer is never deleted - yeah, it's intended memory leak. - // It is necessary to prevent problems when user's signal handler calls exit function - // which destroys all global variables including this one. - // It such situation we have 2 options: - // - wait for auxiliary thread to die - which will cause dead lock - // - destruct variable, ignoring thread - which will cause data corruption. + }; + + // This pointer is never deleted - yeah, it's intended memory leak. + // It is necessary to prevent problems when user's signal handler calls exit function + // which destroys all global variables including this one. + // It such situation we have 2 options: + // - wait for auxiliary thread to die - which will cause dead lock + // - destruct variable, ignoring thread - which will cause data corruption. TAsyncSignalsHandler* SIGNALS_HANDLER = nullptr; -} +} void SetAsyncSignalHandler(int signum, TAutoPtr<TEventHandler> handler) { static TAtomic lock; - + if (Y_UNLIKELY(SIGNALS_HANDLER == nullptr)) { TGuard<TAtomic> dnd(lock); - + if (SIGNALS_HANDLER == nullptr) { // NEVERS GETS DESTROYED SIGNALS_HANDLER = new TAsyncSignalsHandler(); } } - + SIGNALS_HANDLER->Install(signum, handler); } @@ -218,25 +218,25 @@ namespace { template <typename TFunc> class TFunctionEventHandler: public TEventHandler { TFunc Func; - + public: TFunctionEventHandler(TFunc func) { if (func) Func = func; - } + } int Handle(int signum) override { - if (Func) { - Func(signum); - } - + if (Func) { + Func(signum); + } + return 0; } }; } void SetAsyncSignalHandler(int signum, void (*handler)(int)) { - SetAsyncSignalHandler(signum, new TFunctionEventHandler<void (*)(int)>(handler)); + SetAsyncSignalHandler(signum, new TFunctionEventHandler<void (*)(int)>(handler)); } void SetAsyncSignalFunction(int signum, std::function<void(int)> func) { |