pthread_cancel.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #include "pthread_impl.h"
  2. #include "syscall.h"
  3. void __cancel()
  4. {
  5. pthread_t self = __pthread_self();
  6. self->canceldisable = 1;
  7. self->cancelasync = 0;
  8. pthread_exit(PTHREAD_CANCELED);
  9. }
  10. long __syscall_cp_asm(volatile void *, syscall_arg_t,
  11. syscall_arg_t, syscall_arg_t, syscall_arg_t,
  12. syscall_arg_t, syscall_arg_t, syscall_arg_t);
  13. long __syscall_cp_c(syscall_arg_t nr,
  14. syscall_arg_t u, syscall_arg_t v, syscall_arg_t w,
  15. syscall_arg_t x, syscall_arg_t y, syscall_arg_t z)
  16. {
  17. pthread_t self;
  18. long r;
  19. if (!libc.has_thread_pointer || (self = __pthread_self())->canceldisable)
  20. return __syscall(nr, u, v, w, x, y, z);
  21. r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z);
  22. if (r==-EINTR && nr!=SYS_close && self->cancel && !self->canceldisable)
  23. __cancel();
  24. return r;
  25. }
  26. static void _sigaddset(sigset_t *set, int sig)
  27. {
  28. unsigned s = sig-1;
  29. set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1);
  30. }
  31. static void cancel_handler(int sig, siginfo_t *si, void *ctx)
  32. {
  33. pthread_t self = __pthread_self();
  34. ucontext_t *uc = ctx;
  35. const char *ip = ((char **)&uc->uc_mcontext)[CANCEL_REG_IP];
  36. extern const char __cp_begin[1], __cp_end[1];
  37. if (!self->cancel || self->canceldisable) return;
  38. _sigaddset(&uc->uc_sigmask, SIGCANCEL);
  39. if (self->cancelasync || ip >= __cp_begin && ip < __cp_end) {
  40. self->canceldisable = 1;
  41. pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0);
  42. __cancel();
  43. }
  44. __syscall(SYS_tkill, self->tid, SIGCANCEL);
  45. }
  46. void __testcancel()
  47. {
  48. if (!libc.has_thread_pointer) return;
  49. pthread_t self = __pthread_self();
  50. if (self->cancel && !self->canceldisable)
  51. __cancel();
  52. }
  53. static void init_cancellation()
  54. {
  55. struct sigaction sa = {
  56. .sa_flags = SA_SIGINFO | SA_RESTART,
  57. .sa_sigaction = cancel_handler
  58. };
  59. sigfillset(&sa.sa_mask);
  60. __libc_sigaction(SIGCANCEL, &sa, 0);
  61. }
  62. int pthread_cancel(pthread_t t)
  63. {
  64. static int init;
  65. if (!init) {
  66. init_cancellation();
  67. init = 1;
  68. }
  69. a_store(&t->cancel, 1);
  70. return pthread_kill(t, SIGCANCEL);
  71. }