synccall.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #include "pthread_impl.h"
  2. #include <semaphore.h>
  3. static struct chain {
  4. struct chain *next;
  5. sem_t sem, sem2;
  6. } *head, *cur;
  7. static void (*callback)(void *), *context;
  8. static int chainlen;
  9. static sem_t chainlock, chaindone;
  10. static pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
  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. /* Threads which have already decremented themselves from the
  19. * thread count must not act. Block further receipt of signals
  20. * and return. */
  21. if (self->dead) {
  22. memset(&((ucontext_t *)ctx)->uc_sigmask, -1, 8);
  23. errno = old_errno;
  24. return;
  25. }
  26. sem_init(&ch.sem, 0, 0);
  27. sem_init(&ch.sem2, 0, 0);
  28. while (sem_wait(&chainlock));
  29. ch.next = head;
  30. head = &ch;
  31. if (++chainlen == libc.threads_minus_1) sem_post(&chaindone);
  32. sem_post(&chainlock);
  33. while (sem_wait(&ch.sem));
  34. callback(context);
  35. sem_post(&ch.sem2);
  36. while (sem_wait(&ch.sem));
  37. errno = old_errno;
  38. }
  39. void __synccall(void (*func)(void *), void *ctx)
  40. {
  41. pthread_t self;
  42. struct sigaction sa;
  43. struct chain *next;
  44. uint64_t oldmask;
  45. if (!libc.threads_minus_1) {
  46. func(ctx);
  47. return;
  48. }
  49. pthread_rwlock_wrlock(&lock);
  50. __syscall(SYS_rt_sigprocmask, SIG_BLOCK, (uint64_t[]){-1}, &oldmask, 8);
  51. sem_init(&chaindone, 0, 0);
  52. sem_init(&chainlock, 0, 1);
  53. chainlen = 0;
  54. callback = func;
  55. context = ctx;
  56. sa.sa_flags = SA_SIGINFO | SA_RESTART;
  57. sa.sa_sigaction = handler;
  58. sigfillset(&sa.sa_mask);
  59. __libc_sigaction(SIGSYNCCALL, &sa, 0);
  60. self = __pthread_self();
  61. sigqueue(self->pid, SIGSYNCCALL, (union sigval){0});
  62. while (sem_wait(&chaindone));
  63. for (cur=head; cur; cur=cur->next) {
  64. sem_post(&cur->sem);
  65. while (sem_wait(&cur->sem2));
  66. }
  67. func(ctx);
  68. for (cur=head; cur; cur=next) {
  69. next = cur->next;
  70. sem_post(&cur->sem);
  71. }
  72. sa.sa_flags = 0;
  73. sa.sa_handler = SIG_IGN;
  74. __libc_sigaction(SIGSYNCCALL, &sa, 0);
  75. __syscall(SYS_rt_sigprocmask, SIG_SETMASK, &oldmask, 0, 8);
  76. pthread_rwlock_unlock(&lock);
  77. }
  78. void __synccall_lock()
  79. {
  80. pthread_rwlock_rdlock(&lock);
  81. }
  82. void __synccall_unlock()
  83. {
  84. pthread_rwlock_unlock(&lock);
  85. }