signals.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include "signals.h"
  2. #include "utils.h"
  3. #include <yql/essentials/utils/log/log.h>
  4. #include <yql/essentials/utils/backtrace/backtrace.h>
  5. #include <contrib/ydb/library/yql/providers/yt/lib/log/yt_logger.h>
  6. #include <util/stream/output.h>
  7. #include <util/generic/yexception.h>
  8. #include <util/datetime/base.h>
  9. #include <util/network/socket.h>
  10. #include <util/system/getpid.h>
  11. #ifdef _linux_
  12. # include <sys/prctl.h>
  13. #endif
  14. #include <string.h>
  15. #include <signal.h>
  16. #include <errno.h>
  17. #include <stdlib.h>
  18. namespace NYql {
  19. volatile sig_atomic_t NeedTerminate = 0;
  20. volatile sig_atomic_t NeedQuit = 0;
  21. volatile sig_atomic_t NeedReconfigure = 0;
  22. volatile sig_atomic_t NeedReopenLog = 0;
  23. volatile sig_atomic_t NeedReapZombies = 0;
  24. volatile sig_atomic_t NeedInterrupt = 0;
  25. volatile sig_atomic_t CatchInterrupt = 0;
  26. TPipe SignalPipeW;
  27. TPipe SignalPipeR;
  28. namespace {
  29. void SignalHandler(int signo)
  30. {
  31. switch (signo) {
  32. case SIGTERM:
  33. NeedTerminate = 1;
  34. break;
  35. case SIGQUIT:
  36. NeedQuit = 1;
  37. break;
  38. #ifdef _unix_
  39. case SIGHUP:
  40. NeedReconfigure = 1;
  41. break;
  42. case SIGUSR1:
  43. NeedReopenLog = 1;
  44. break;
  45. case SIGCHLD:
  46. NeedReapZombies = 1;
  47. break;
  48. #endif
  49. case SIGINT:
  50. if (CatchInterrupt) {
  51. NeedInterrupt = 1;
  52. } else {
  53. fprintf(stderr, "%s (pid=%d) captured SIGINT\n",
  54. GetProcTitle(), getpid());
  55. signal(signo, SIG_DFL);
  56. raise(signo);
  57. }
  58. break;
  59. default:
  60. break;
  61. }
  62. }
  63. void SignalHandlerWithSelfPipe(int signo)
  64. {
  65. SignalHandler(signo);
  66. int savedErrno = errno;
  67. if (write(SignalPipeW.GetHandle(), "x", 1) == -1 && errno != EAGAIN) {
  68. static TStringBuf msg("cannot write to signal pipe");
  69. #ifndef STDERR_FILENO
  70. #define STDERR_FILENO 2
  71. #endif
  72. write(STDERR_FILENO, msg.data(), msg.size());
  73. abort();
  74. }
  75. errno = savedErrno;
  76. }
  77. #ifndef _unix_
  78. const char* strsignal(int signo)
  79. {
  80. switch (signo) {
  81. case SIGTERM: return "SIGTERM";
  82. case SIGINT: return "SIGINT";
  83. case SIGQUIT: return "SIGQUIT";
  84. default:
  85. return "UNKNOWN";
  86. }
  87. }
  88. #endif
  89. namespace {
  90. class TEmergencyLogOutput: public IOutputStream {
  91. public:
  92. TEmergencyLogOutput()
  93. : Current_(Buf_)
  94. , End_(Y_ARRAY_END(Buf_))
  95. {
  96. }
  97. ~TEmergencyLogOutput() {
  98. }
  99. private:
  100. inline size_t Avail() const noexcept {
  101. return End_ - Current_;
  102. }
  103. void DoFlush() override {
  104. if (Current_ != Buf_) {
  105. NYql::NLog::YqlLogger().Write(TLOG_EMERG, Buf_, Current_ - Buf_);
  106. Current_ = Buf_;
  107. }
  108. }
  109. void DoWrite(const void* buf, size_t len) override {
  110. len = Min(len, Avail());
  111. if (len) {
  112. char* end = Current_ + len;
  113. memcpy(Current_, buf, len);
  114. Current_ = end;
  115. }
  116. }
  117. private:
  118. char Buf_[1 << 20];
  119. char* Current_;
  120. char* const End_;
  121. };
  122. TEmergencyLogOutput EMERGENCY_LOG_OUT;
  123. }
  124. void LogBacktraceOnSignal(int signum)
  125. {
  126. if (NYql::NLog::IsYqlLoggerInitialized()) {
  127. EMERGENCY_LOG_OUT << strsignal(signum) << TStringBuf(" (pid=") << GetPID() << TStringBuf("): ");
  128. NYql::NBacktrace::KikimrBackTraceFormatImpl(&EMERGENCY_LOG_OUT);
  129. EMERGENCY_LOG_OUT.Flush();
  130. }
  131. NYql::FlushYtDebugLog();
  132. /* Now reraise the signal. We reactivate the signal’s default handling,
  133. which is to terminate the process. We could just call exit or abort,
  134. but reraising the signal sets the return status from the process
  135. correctly. */
  136. raise(signum);
  137. }
  138. #ifdef _unix_
  139. int SetSignalHandler(int signo, void (*handler)(int))
  140. {
  141. struct sigaction sa;
  142. sa.sa_flags = SA_RESTART;
  143. sa.sa_handler = handler;
  144. sigemptyset(&sa.sa_mask);
  145. return sigaction(signo, &sa, nullptr);
  146. }
  147. #else
  148. int SetSignalHandler(int signo, void (*handler)(int))
  149. {
  150. return (signal(signo, handler) == SIG_ERR) ? -1 : 0;
  151. }
  152. #endif
  153. struct TSignalHandlerDesc
  154. {
  155. int signo;
  156. void (*handler)(int);
  157. };
  158. void SetSignalHandlers(const TSignalHandlerDesc* handlerDescs)
  159. {
  160. sigset_t interestedSignals;
  161. SigEmptySet(&interestedSignals);
  162. for (int i = 0; handlerDescs[i].signo != -1; i++) {
  163. int signo = handlerDescs[i].signo;
  164. SigAddSet(&interestedSignals, signo);
  165. if (SetSignalHandler(signo, handlerDescs[i].handler) == -1) {
  166. ythrow TSystemError() << "Cannot set handler for signal "
  167. << strsignal(signo);
  168. }
  169. }
  170. if (SigProcMask(SIG_BLOCK, &interestedSignals, NULL) == -1) {
  171. ythrow TSystemError() << "Cannot set sigprocmask";
  172. }
  173. NYql::NBacktrace::AddAfterFatalCallback([](int signo){ LogBacktraceOnSignal(signo); });
  174. NYql::NBacktrace::RegisterKikimrFatalActions();
  175. }
  176. } // namespace
  177. void InitSignals()
  178. {
  179. TSignalHandlerDesc handlerDescs[] = {
  180. { SIGTERM, SignalHandler },
  181. { SIGINT, SignalHandler },
  182. { SIGQUIT, SignalHandler },
  183. #ifdef _unix_
  184. { SIGPIPE, SIG_IGN },
  185. { SIGHUP, SignalHandler },
  186. { SIGUSR1, SignalHandler },
  187. { SIGCHLD, SignalHandler },
  188. #endif
  189. { -1, nullptr }
  190. };
  191. SetSignalHandlers(handlerDescs);
  192. }
  193. void InitSignalsWithSelfPipe()
  194. {
  195. TSignalHandlerDesc handlerDescs[] = {
  196. { SIGTERM, SignalHandlerWithSelfPipe },
  197. { SIGINT, SignalHandlerWithSelfPipe },
  198. { SIGQUIT, SignalHandlerWithSelfPipe },
  199. #ifdef _unix_
  200. { SIGPIPE, SIG_IGN },
  201. { SIGHUP, SignalHandlerWithSelfPipe },
  202. { SIGUSR1, SignalHandlerWithSelfPipe },
  203. { SIGCHLD, SignalHandlerWithSelfPipe },
  204. #endif
  205. { -1, nullptr }
  206. };
  207. TPipe::Pipe(SignalPipeR, SignalPipeW);
  208. SetNonBlock(SignalPipeR.GetHandle());
  209. SetNonBlock(SignalPipeW.GetHandle());
  210. SetSignalHandlers(handlerDescs);
  211. }
  212. void CatchInterruptSignal(bool doCatch) {
  213. CatchInterrupt = doCatch;
  214. }
  215. void SigSuspend(const sigset_t* mask)
  216. {
  217. #ifdef _unix_
  218. sigsuspend(mask);
  219. #else
  220. Y_UNUSED(mask);
  221. Sleep(TDuration::Seconds(1));
  222. #endif
  223. }
  224. void AllowAnySignals()
  225. {
  226. sigset_t blockMask;
  227. SigEmptySet(&blockMask);
  228. if (SigProcMask(SIG_SETMASK, &blockMask, NULL) == -1) {
  229. ythrow TSystemError() << "Cannot set sigprocmask";
  230. }
  231. }
  232. bool HasPendingQuitOrTerm() {
  233. #ifdef _unix_
  234. sigset_t signals;
  235. SigEmptySet(&signals);
  236. if (sigpending(&signals)) {
  237. ythrow TSystemError() << "Error in sigpending";
  238. }
  239. return (SigIsMember(&signals, SIGQUIT) == 1) || (SigIsMember(&signals, SIGTERM) == 1);
  240. #else
  241. return false;
  242. #endif
  243. }
  244. } // namespace NYql