signal.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
  2. *
  3. * Data Differential Utility library
  4. *
  5. * Copyright (C) 2012 Data Differential, http://datadifferential.com/
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * * Redistributions in binary form must reproduce the above
  15. * copyright notice, this list of conditions and the following disclaimer
  16. * in the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * * The names of its contributors may not be used to endorse or
  20. * promote products derived from this software without specific prior
  21. * written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  26. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  27. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  28. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  29. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  30. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  31. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  32. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  33. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. */
  36. #include "gear_config.h"
  37. #include <fcntl.h>
  38. #include <semaphore.h>
  39. #include <sys/stat.h>
  40. #include <unistd.h>
  41. #include <cassert>
  42. #include <cerrno>
  43. #include <csignal>
  44. #include <cstdlib>
  45. #include <cstring>
  46. #include <iostream>
  47. #include <util/signal.hpp>
  48. namespace datadifferential {
  49. namespace util {
  50. #define MAGIC_MEMORY 123569
  51. bool SignalThread::is_shutdown()
  52. {
  53. bool ret;
  54. pthread_mutex_lock(&shutdown_mutex);
  55. ret= bool(__shutdown != SHUTDOWN_RUNNING);
  56. pthread_mutex_unlock(&shutdown_mutex);
  57. return ret;
  58. }
  59. void SignalThread::set_shutdown(shutdown_t arg)
  60. {
  61. pthread_mutex_lock(&shutdown_mutex);
  62. __shutdown= arg;
  63. pthread_mutex_unlock(&shutdown_mutex);
  64. if (arg == SHUTDOWN_GRACEFUL)
  65. {
  66. if (pthread_kill(thread, SIGUSR2) == 0)
  67. {
  68. void *retval;
  69. pthread_join(thread, &retval);
  70. }
  71. }
  72. }
  73. shutdown_t SignalThread::get_shutdown()
  74. {
  75. shutdown_t local;
  76. pthread_mutex_lock(&shutdown_mutex);
  77. local= __shutdown;
  78. pthread_mutex_unlock(&shutdown_mutex);
  79. return local;
  80. }
  81. void SignalThread::post()
  82. {
  83. sem_post(lock);
  84. }
  85. void SignalThread::test()
  86. {
  87. (void)magic_memory;
  88. assert(magic_memory == MAGIC_MEMORY);
  89. assert(sigismember(&set, SIGABRT));
  90. assert(sigismember(&set, SIGINT));
  91. assert(sigismember(&set, SIGQUIT));
  92. assert(sigismember(&set, SIGTERM));
  93. assert(sigismember(&set, SIGUSR2));
  94. }
  95. void SignalThread::sighup(signal_callback_fn* arg)
  96. {
  97. _sighup= arg;
  98. }
  99. std::string SignalThread::random_lock_name(std::string::size_type len = 10)
  100. {
  101. static auto& chrs = "0123456789"
  102. "abcdefghijklmnopqrstuvwxyz"
  103. "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  104. thread_local static std::mt19937 rg{std::random_device{}()};
  105. thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);
  106. // convenient to named semaphore definition
  107. // http://man7.org/linux/man-pages/man7/sem_overview.7.html
  108. std::string s{"/"};
  109. s.reserve(len--);
  110. while (len--)
  111. {
  112. s += chrs[pick(rg)];
  113. }
  114. return s;
  115. }
  116. void SignalThread::sighup()
  117. {
  118. if (_sighup)
  119. {
  120. _sighup();
  121. }
  122. }
  123. SignalThread::~SignalThread()
  124. {
  125. if (not is_shutdown())
  126. {
  127. set_shutdown(SHUTDOWN_GRACEFUL);
  128. }
  129. #if 0
  130. if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
  131. {
  132. void *retval;
  133. pthread_join(thread, &retval);
  134. }
  135. #endif
  136. sem_close(lock);
  137. }
  138. extern "C" {
  139. static void *sig_thread(void *arg)
  140. {
  141. SignalThread *context= (SignalThread*)arg;
  142. context->test();
  143. context->post();
  144. while (context->get_shutdown() == SHUTDOWN_RUNNING)
  145. {
  146. int sig;
  147. if (context->wait(sig) == -1)
  148. {
  149. std::cerr << "sigwait() returned errno:" << strerror(errno) << std::endl;
  150. continue;
  151. }
  152. switch (sig)
  153. {
  154. case SIGUSR2:
  155. break;
  156. case SIGHUP:
  157. context->sighup();
  158. break;
  159. case SIGABRT:
  160. case SIGINT:
  161. case SIGQUIT:
  162. case SIGTERM:
  163. if (context->is_shutdown() == false)
  164. {
  165. context->set_shutdown(SHUTDOWN_FORCED);
  166. }
  167. if (context->exit_on_signal())
  168. {
  169. exit(EXIT_SUCCESS);
  170. }
  171. break;
  172. default:
  173. std::cerr << "Signal handling thread got unexpected signal " << strsignal(sig) << std::endl;
  174. break;
  175. }
  176. }
  177. return NULL;
  178. }
  179. }
  180. SignalThread::SignalThread(bool exit_on_signal_arg) :
  181. _exit_on_signal(exit_on_signal_arg),
  182. magic_memory(MAGIC_MEMORY),
  183. __shutdown(SHUTDOWN_RUNNING),
  184. thread(pthread_self()),
  185. _sighup(NULL)
  186. {
  187. pthread_mutex_init(&shutdown_mutex, NULL);
  188. sigemptyset(&set);
  189. sigaddset(&set, SIGABRT);
  190. sigaddset(&set, SIGINT);
  191. sigaddset(&set, SIGQUIT);
  192. sigaddset(&set, SIGTERM);
  193. sigaddset(&set, SIGUSR2);
  194. }
  195. bool SignalThread::setup()
  196. {
  197. set_shutdown(SHUTDOWN_RUNNING);
  198. int error;
  199. if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
  200. {
  201. std::cerr << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")" << std::endl;
  202. return false;
  203. }
  204. if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
  205. {
  206. std::cerr << "pthread_create() died during pthread_create(" << strerror(error) << ")" << std::endl;
  207. return false;
  208. }
  209. const char * lock_name = random_lock_name().c_str();
  210. lock = sem_open(lock_name, O_CREAT|O_EXCL, S_IRUSR|S_IWUSR, 0);
  211. if (lock == SEM_FAILED) {
  212. std::cerr << "WARNING: sem_open failed(" << strerror(errno) << ")"
  213. << " when opening lock '" << lock_name << "'." << std::endl;
  214. } else {
  215. sem_wait(lock);
  216. }
  217. return true;
  218. }
  219. } /* namespace util */
  220. } /* namespace datadifferential */