+ pid = __syscall(SYS_getpid);
+ self = __syscall(SYS_gettid);
+
+ /* Since opendir is not AS-safe, the DIR needs to be setup manually
+ * in automatic storage. Thankfully this is easy. */
+ dir.fd = open("/proc/self/task", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ if (dir.fd < 0) goto out;
+
+ /* Initially send one signal per counted thread. But since we can't
+ * synchronize with thread creation/exit here, there could be too
+ * few signals. This initial signaling is just an optimization, not
+ * part of the logic. */
+ for (i=libc.threads_minus_1; i; i--)
+ __syscall(SYS_kill, pid, SIGSYNCCALL);
+
+ /* Loop scanning the kernel-provided thread list until it shows no
+ * threads that have not already replied to the signal. */
+ for (;;) {
+ int miss_cnt = 0;
+ while ((de = readdir(&dir))) {
+ if (!isdigit(de->d_name[0])) continue;
+ int tid = atoi(de->d_name);
+ if (tid == self || !tid) continue;
+
+ /* Set the target thread as the PI futex owner before
+ * checking if it's in the list of caught threads. If it
+ * adds itself to the list after we check for it, then
+ * it will see its own tid in the PI futex and perform
+ * the unlock operation. */
+ a_store(&target_tid, tid);
+
+ /* Thread-already-caught is a success condition. */
+ for (cp = head; cp && cp->tid != tid; cp=cp->next);
+ if (cp) continue;
+
+ r = -__syscall(SYS_tgkill, pid, tid, SIGSYNCCALL);
+
+ /* Target thread exit is a success condition. */
+ if (r == ESRCH) continue;
+
+ /* The FUTEX_LOCK_PI operation is used to loan priority
+ * to the target thread, which otherwise may be unable
+ * to run. Timeout is necessary because there is a race
+ * condition where the tid may be reused by a different
+ * process. */
+ clock_gettime(CLOCK_REALTIME, &ts);
+ ts.tv_nsec += 10000000;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+ r = -__syscall(SYS_futex, &target_tid,
+ FUTEX_LOCK_PI|FUTEX_PRIVATE, 0, &ts);
+
+ /* Obtaining the lock means the thread responded. ESRCH
+ * means the target thread exited, which is okay too. */
+ if (!r || r == ESRCH) continue;
+
+ miss_cnt++;
+ }
+ if (!miss_cnt) break;
+ rewinddir(&dir);