sigaction.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* POSIX compatible signal blocking.
  2. Copyright (C) 2008-2011 Free Software Foundation, Inc.
  3. Written by Eric Blake <ebb9@byu.net>, 2008.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. #include <config.h>
  15. /* Specification. */
  16. #include <signal.h>
  17. #include <errno.h>
  18. #include <stdint.h>
  19. #include <stdlib.h>
  20. /* This implementation of sigaction is tailored to Woe32 behavior:
  21. signal() has SysV semantics (ie. the handler is uninstalled before
  22. it is invoked). This is an inherent data race if an asynchronous
  23. signal is sent twice in a row before we can reinstall our handler,
  24. but there's nothing we can do about it. Meanwhile, sigprocmask()
  25. is not present, and while we can use the gnulib replacement to
  26. provide critical sections, it too suffers from potential data races
  27. in the face of an ill-timed asynchronous signal. And we compound
  28. the situation by reading static storage in a signal handler, which
  29. POSIX warns is not generically async-signal-safe. Oh well.
  30. Additionally:
  31. - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD
  32. is not defined.
  33. - We don't implement SA_ONSTACK, because sigaltstack() is not present.
  34. - We ignore SA_RESTART, because blocking Win32 calls are not interrupted
  35. anyway when an asynchronous signal occurs, and the MSVCRT runtime
  36. never sets errno to EINTR.
  37. - We don't implement SA_SIGINFO because it is impossible to do so
  38. portably.
  39. POSIX states that an application should not mix signal() and
  40. sigaction(). We support the use of signal() within the gnulib
  41. sigprocmask() substitute, but all other application code linked
  42. with this module should stick with only sigaction(). */
  43. /* Check some of our assumptions. */
  44. #if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT
  45. # error "Revisit the assumptions made in the sigaction module"
  46. #endif
  47. /* Out-of-range substitutes make a good fallback for uncatchable
  48. signals. */
  49. #ifndef SIGKILL
  50. # define SIGKILL (-1)
  51. #endif
  52. #ifndef SIGSTOP
  53. # define SIGSTOP (-1)
  54. #endif
  55. /* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias
  56. for the signal SIGABRT. Only one signal handler is stored for both
  57. SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */
  58. #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  59. # undef SIGABRT_COMPAT
  60. # define SIGABRT_COMPAT 6
  61. #endif
  62. /* A signal handler. */
  63. typedef void (*handler_t) (int signal);
  64. /* Set of current actions. If sa_handler for an entry is NULL, then
  65. that signal is not currently handled by the sigaction handler. */
  66. static struct sigaction volatile action_array[NSIG] /* = 0 */;
  67. /* Signal handler that is installed for signals. */
  68. static void
  69. sigaction_handler (int sig)
  70. {
  71. handler_t handler;
  72. sigset_t mask;
  73. sigset_t oldmask;
  74. int saved_errno = errno;
  75. if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler)
  76. {
  77. /* Unexpected situation; be careful to avoid recursive abort. */
  78. if (sig == SIGABRT)
  79. signal (SIGABRT, SIG_DFL);
  80. abort ();
  81. }
  82. /* Reinstall the signal handler when required; otherwise update the
  83. bookkeeping so that the user's handler may call sigaction and get
  84. accurate results. We know the signal isn't currently blocked, or
  85. we wouldn't be in its handler, therefore we know that we are not
  86. interrupting a sigaction() call. There is a race where any
  87. asynchronous instance of the same signal occurring before we
  88. reinstall the handler will trigger the default handler; oh
  89. well. */
  90. handler = action_array[sig].sa_handler;
  91. if ((action_array[sig].sa_flags & SA_RESETHAND) == 0)
  92. signal (sig, sigaction_handler);
  93. else
  94. action_array[sig].sa_handler = NULL;
  95. /* Block appropriate signals. */
  96. mask = action_array[sig].sa_mask;
  97. if ((action_array[sig].sa_flags & SA_NODEFER) == 0)
  98. sigaddset (&mask, sig);
  99. sigprocmask (SIG_BLOCK, &mask, &oldmask);
  100. /* Invoke the user's handler, then restore prior mask. */
  101. errno = saved_errno;
  102. handler (sig);
  103. saved_errno = errno;
  104. sigprocmask (SIG_SETMASK, &oldmask, NULL);
  105. errno = saved_errno;
  106. }
  107. /* Change and/or query the action that will be taken on delivery of
  108. signal SIG. If not NULL, ACT describes the new behavior. If not
  109. NULL, OACT is set to the prior behavior. Return 0 on success, or
  110. set errno and return -1 on failure. */
  111. int
  112. sigaction (int sig, const struct sigaction *restrict act,
  113. struct sigaction *restrict oact)
  114. {
  115. sigset_t mask;
  116. sigset_t oldmask;
  117. int saved_errno;
  118. if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP
  119. || (act && act->sa_handler == SIG_ERR))
  120. {
  121. errno = EINVAL;
  122. return -1;
  123. }
  124. #ifdef SIGABRT_COMPAT
  125. if (sig == SIGABRT_COMPAT)
  126. sig = SIGABRT;
  127. #endif
  128. /* POSIX requires sigaction() to be async-signal-safe. In other
  129. words, if an asynchronous signal can occur while we are anywhere
  130. inside this function, the user's handler could then call
  131. sigaction() recursively and expect consistent results. We meet
  132. this rule by using sigprocmask to block all signals before
  133. modifying any data structure that could be read from a signal
  134. handler; this works since we know that the gnulib sigprocmask
  135. replacement does not try to use sigaction() from its handler. */
  136. if (!act && !oact)
  137. return 0;
  138. sigfillset (&mask);
  139. sigprocmask (SIG_BLOCK, &mask, &oldmask);
  140. if (oact)
  141. {
  142. if (action_array[sig].sa_handler)
  143. *oact = action_array[sig];
  144. else
  145. {
  146. /* Safe to change the handler at will here, since all
  147. signals are currently blocked. */
  148. oact->sa_handler = signal (sig, SIG_DFL);
  149. if (oact->sa_handler == SIG_ERR)
  150. goto failure;
  151. signal (sig, oact->sa_handler);
  152. oact->sa_flags = SA_RESETHAND | SA_NODEFER;
  153. sigemptyset (&oact->sa_mask);
  154. }
  155. }
  156. if (act)
  157. {
  158. /* Safe to install the handler before updating action_array,
  159. since all signals are currently blocked. */
  160. if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN)
  161. {
  162. if (signal (sig, act->sa_handler) == SIG_ERR)
  163. goto failure;
  164. action_array[sig].sa_handler = NULL;
  165. }
  166. else
  167. {
  168. if (signal (sig, sigaction_handler) == SIG_ERR)
  169. goto failure;
  170. action_array[sig] = *act;
  171. }
  172. }
  173. sigprocmask (SIG_SETMASK, &oldmask, NULL);
  174. return 0;
  175. failure:
  176. saved_errno = errno;
  177. sigprocmask (SIG_SETMASK, &oldmask, NULL);
  178. errno = saved_errno;
  179. return -1;
  180. }