catch-signal.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* Convenience function to catch expected signals during an operation.
  2. Copyright (C) 1996-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library 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 GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <hurd/signal.h>
  16. #include <hurd/sigpreempt.h>
  17. #include <string.h>
  18. #include <assert.h>
  19. error_t
  20. __hurd_catch_signal (sigset_t sigset,
  21. unsigned long int first, unsigned long int last,
  22. error_t (*operate) (struct hurd_signal_preemptor *),
  23. sighandler_t handler)
  24. {
  25. /* We need to restore the signal mask, because otherwise the
  26. signal-handling code will have blocked the caught signal and for
  27. instance calling hurd_catch_signal again would then dump core. */
  28. sigjmp_buf buf;
  29. void throw (int signo, long int sigcode, struct sigcontext *scp)
  30. { siglongjmp (buf, scp->sc_error ?: EGRATUITOUS); }
  31. struct hurd_signal_preemptor preemptor =
  32. {
  33. sigset, first, last,
  34. NULL, handler == SIG_ERR ? (sighandler_t) &throw : handler,
  35. };
  36. struct hurd_sigstate *const ss = _hurd_self_sigstate ();
  37. error_t error;
  38. if (handler != SIG_ERR)
  39. /* Not our handler; don't bother saving state. */
  40. error = 0;
  41. else
  42. /* This returns again with nonzero value when we preempt a signal. */
  43. error = sigsetjmp (buf, 1);
  44. if (error == 0)
  45. {
  46. /* Install a signal preemptor for the thread. */
  47. __spin_lock (&ss->lock);
  48. preemptor.next = ss->preemptors;
  49. ss->preemptors = &preemptor;
  50. __spin_unlock (&ss->lock);
  51. /* Try the operation that might crash. */
  52. (*operate) (&preemptor);
  53. }
  54. /* Either FUNCTION completed happily and ERROR is still zero, or it hit
  55. an expected signal and `throw' made setjmp return the signal error
  56. code in ERROR. Now we can remove the preemptor and return. */
  57. __spin_lock (&ss->lock);
  58. assert (ss->preemptors == &preemptor);
  59. ss->preemptors = preemptor.next;
  60. __spin_unlock (&ss->lock);
  61. return error;
  62. }
  63. strong_alias (__hurd_catch_signal, hurd_catch_signal)
  64. error_t
  65. hurd_safe_memset (void *dest, int byte, size_t nbytes)
  66. {
  67. error_t operate (struct hurd_signal_preemptor *preemptor)
  68. {
  69. memset (dest, byte, nbytes);
  70. return 0;
  71. }
  72. return __hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
  73. (vm_address_t) dest, (vm_address_t) dest + nbytes,
  74. &operate, SIG_ERR);
  75. }
  76. error_t
  77. hurd_safe_copyout (void *dest, const void *src, size_t nbytes)
  78. {
  79. error_t operate (struct hurd_signal_preemptor *preemptor)
  80. {
  81. memcpy (dest, src, nbytes);
  82. return 0;
  83. }
  84. return __hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
  85. (vm_address_t) dest, (vm_address_t) dest + nbytes,
  86. &operate, SIG_ERR);
  87. }
  88. error_t
  89. hurd_safe_copyin (void *dest, const void *src, size_t nbytes)
  90. {
  91. error_t operate (struct hurd_signal_preemptor *preemptor)
  92. {
  93. memcpy (dest, src, nbytes);
  94. return 0;
  95. }
  96. return __hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
  97. (vm_address_t) src, (vm_address_t) src + nbytes,
  98. &operate, SIG_ERR);
  99. }
  100. error_t
  101. hurd_safe_memmove (void *dest, const void *src, size_t nbytes)
  102. {
  103. jmp_buf buf;
  104. void throw (int signo, long int sigcode, struct sigcontext *scp)
  105. { longjmp (buf, scp->sc_error ?: EGRATUITOUS); }
  106. struct hurd_signal_preemptor src_preemptor =
  107. {
  108. sigmask (SIGBUS) | sigmask (SIGSEGV),
  109. (vm_address_t) src, (vm_address_t) src + nbytes,
  110. NULL, (sighandler_t) &throw,
  111. };
  112. struct hurd_signal_preemptor dest_preemptor =
  113. {
  114. sigmask (SIGBUS) | sigmask (SIGSEGV),
  115. (vm_address_t) dest, (vm_address_t) dest + nbytes,
  116. NULL, (sighandler_t) &throw,
  117. &src_preemptor
  118. };
  119. struct hurd_sigstate *const ss = _hurd_self_sigstate ();
  120. error_t error;
  121. /* This returns again with nonzero value when we preempt a signal. */
  122. error = setjmp (buf);
  123. if (error == 0)
  124. {
  125. /* Install a signal preemptor for the thread. */
  126. __spin_lock (&ss->lock);
  127. src_preemptor.next = ss->preemptors;
  128. ss->preemptors = &dest_preemptor;
  129. __spin_unlock (&ss->lock);
  130. /* Do the copy; it might fault. */
  131. memmove (dest, src, nbytes);
  132. }
  133. /* Either memmove completed happily and ERROR is still zero, or it hit
  134. an expected signal and `throw' made setjmp return the signal error
  135. code in ERROR. Now we can remove the preemptor and return. */
  136. __spin_lock (&ss->lock);
  137. assert (ss->preemptors == &dest_preemptor);
  138. ss->preemptors = src_preemptor.next;
  139. __spin_unlock (&ss->lock);
  140. return error;
  141. }