sigaction.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #include <signal.h>
  2. #include <errno.h>
  3. #include <string.h>
  4. #include "syscall.h"
  5. #include "pthread_impl.h"
  6. #include "libc.h"
  7. #include "ksigaction.h"
  8. volatile int dummy_lock[1] = { 0 };
  9. __attribute__((__visibility__("hidden")))
  10. weak_alias(dummy_lock, __abort_lock);
  11. static int unmask_done;
  12. static unsigned long handler_set[_NSIG/(8*sizeof(long))];
  13. void __get_handler_set(sigset_t *set)
  14. {
  15. memcpy(set, handler_set, sizeof handler_set);
  16. }
  17. int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
  18. {
  19. struct k_sigaction ksa, ksa_old;
  20. unsigned long set[_NSIG/(8*sizeof(long))];
  21. if (sa) {
  22. if ((uintptr_t)sa->sa_handler > 1UL) {
  23. a_or_l(handler_set+(sig-1)/(8*sizeof(long)),
  24. 1UL<<(sig-1)%(8*sizeof(long)));
  25. /* If pthread_create has not yet been called,
  26. * implementation-internal signals might not
  27. * yet have been unblocked. They must be
  28. * unblocked before any signal handler is
  29. * installed, so that an application cannot
  30. * receive an illegal sigset_t (with them
  31. * blocked) as part of the ucontext_t passed
  32. * to the signal handler. */
  33. if (!libc.threaded && !unmask_done) {
  34. __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
  35. SIGPT_SET, 0, _NSIG/8);
  36. unmask_done = 1;
  37. }
  38. }
  39. /* Changing the disposition of SIGABRT to anything but
  40. * SIG_DFL requires a lock, so that it cannot be changed
  41. * while abort is terminating the process after simply
  42. * calling raise(SIGABRT) failed to do so. */
  43. if (sa->sa_handler != SIG_DFL && sig == SIGABRT) {
  44. __block_all_sigs(&set);
  45. LOCK(__abort_lock);
  46. }
  47. ksa.handler = sa->sa_handler;
  48. ksa.flags = sa->sa_flags | SA_RESTORER;
  49. ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore;
  50. memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8);
  51. }
  52. int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8);
  53. if (sig == SIGABRT && sa && sa->sa_handler != SIG_DFL) {
  54. UNLOCK(__abort_lock);
  55. __restore_sigs(&set);
  56. }
  57. if (old && !r) {
  58. old->sa_handler = ksa_old.handler;
  59. old->sa_flags = ksa_old.flags;
  60. memcpy(&old->sa_mask, &ksa_old.mask, _NSIG/8);
  61. }
  62. return __syscall_ret(r);
  63. }
  64. int __sigaction(int sig, const struct sigaction *restrict sa, struct sigaction *restrict old)
  65. {
  66. if (sig-32U < 3 || sig-1U >= _NSIG-1) {
  67. errno = EINVAL;
  68. return -1;
  69. }
  70. return __libc_sigaction(sig, sa, old);
  71. }
  72. weak_alias(__sigaction, sigaction);