synccall.c 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #include "pthread_impl.h"
  2. #include <semaphore.h>
  3. #include <string.h>
  4. static struct chain {
  5. struct chain *next;
  6. sem_t sem, sem2;
  7. } *head, *cur;
  8. static void (*callback)(void *), *context;
  9. static int chainlen;
  10. static sem_t chainlock, chaindone;
  11. static void handler(int sig, siginfo_t *si, void *ctx)
  12. {
  13. struct chain ch;
  14. pthread_t self = __pthread_self();
  15. int old_errno = errno;
  16. if (chainlen == libc.threads_minus_1) return;
  17. sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
  18. sem_init(&ch.sem, 0, 0);
  19. sem_init(&ch.sem2, 0, 0);
  20. while (sem_wait(&chainlock));
  21. ch.next = head;
  22. head = &ch;
  23. if (++chainlen == libc.threads_minus_1) sem_post(&chaindone);
  24. sem_post(&chainlock);
  25. while (sem_wait(&ch.sem));
  26. callback(context);
  27. sem_post(&ch.sem2);
  28. while (sem_wait(&ch.sem));
  29. errno = old_errno;
  30. }
  31. void __synccall(void (*func)(void *), void *ctx)
  32. {
  33. pthread_t self;
  34. struct sigaction sa;
  35. struct chain *next;
  36. uint64_t oldmask;
  37. if (!libc.threads_minus_1) {
  38. func(ctx);
  39. return;
  40. }
  41. __inhibit_ptc();
  42. __syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGALL_SET,
  43. &oldmask, _NSIG/8);
  44. sem_init(&chaindone, 0, 0);
  45. sem_init(&chainlock, 0, 1);
  46. chainlen = 0;
  47. callback = func;
  48. context = ctx;
  49. sa.sa_flags = SA_SIGINFO | SA_RESTART;
  50. sa.sa_sigaction = handler;
  51. sigfillset(&sa.sa_mask);
  52. __libc_sigaction(SIGSYNCCALL, &sa, 0);
  53. self = __pthread_self();
  54. sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
  55. while (sem_wait(&chaindone));
  56. for (cur=head; cur; cur=cur->next) {
  57. sem_post(&cur->sem);
  58. while (sem_wait(&cur->sem2));
  59. }
  60. func(ctx);
  61. for (cur=head; cur; cur=next) {
  62. next = cur->next;
  63. sem_post(&cur->sem);
  64. }
  65. sa.sa_flags = 0;
  66. sa.sa_handler = SIG_IGN;
  67. __libc_sigaction(SIGSYNCCALL, &sa, 0);
  68. __syscall(SYS_rt_sigprocmask, SIG_SETMASK,
  69. &oldmask, 0, _NSIG/8);
  70. __release_ptc();
  71. }