return true;
}
-static int get_alive_threads(int own_tid) noexcept
+static int get_alive_threads(int own_tid, bool abort_on_error) noexcept
{
+ auto handle_error = [&]{
+ if (abort_on_error)
+ abort();
+
+ return errno;
+ };
+
// reset alive status
memset(&g_thread_alive, 0, sizeof(g_thread_alive));
auto dir_fd = open("/proc/self/task", O_DIRECTORY | O_CLOEXEC);
if (dir_fd == -1)
- return errno;
+ return handle_error();
char buf[1024];
struct dirent64 *d;
ssize_t nread = getdents64(dir_fd, buf, sizeof(buf));
if (nread == -1) {
close(dir_fd);
- return errno;
+ return handle_error();
}
if (nread == 0)
long tid = strtol(d->d_name, &endptr, 10);
if (errno != 0) {
close(dir_fd);
- return errno;
+ return handle_error();
}
if (tid == own_tid)
return 0;
}
-static int check_threads(int own_tid) noexcept
+static void check_threads(int own_tid) noexcept
{
int ret = 0;
- for (unsigned i = 0; i < 10; ++i) {
- ret = get_alive_threads(own_tid);
+ for (unsigned i = 0; i < 9; ++i) {
+ ret = get_alive_threads(own_tid, false);
if (ret == 0)
- break;
+ return;
/*
* This may happen if a thread disappears, an entry is removed from /proc and getdents64
*/
}
- return ret;
+ get_alive_threads(own_tid, true);
}
static bool no_new_threads() noexcept
return true;
}
-static int signal_and_wait_for_handlers(pid_t own_pid, int own_tid) noexcept
+static void signal_and_wait_for_handlers(pid_t own_pid, int own_tid) noexcept
{
- int ret = 0;
int time_left = MAX_SIG_WAIT_TIME;
do {
- ret = check_threads(own_tid);
- if (ret != 0)
- break;
+ check_threads(own_tid);
for (int i = 0; i < g_managed_tids_num; ++i) {
if (!g_thread_alive[i])
if (ESRCH == err) { // thread already gone - noop
continue;
} else {
- return err;
+ abort();
}
}
} else if (ESRCH == err) { // thread already gone - noop
continue;
} else {
- return err;
+ abort();
}
}
}
// threads that were read some lines above are all sleeping here - BUT - could have
// spawned new threads between reading list from /proc and checking status with count_alive_tids_with_state()
// to make sure the loop can end, here we read /proc again
- ret = check_threads(own_tid);
- if (ret != 0)
- break;
+ check_threads(own_tid);
if (no_new_threads())
// here indeed, no new threads are present and they are all waiting in the signal handler
}
if (time_left == 0)
- return ETIME;
+ abort();
} while (true);
- return ret;
}
static inline int security_manager_sync_threads_internal(const std::string &app_label)
g_th_barrier = 0;
// No allocations allowed beyond this point
- int ret = signal_and_wait_for_handlers(own_pid, own_tid);
- if (ret != 0)
- abort();
+ signal_and_wait_for_handlers(own_pid, own_tid);
// here, all TIDs except current one are waiting to start changing attributes
// We can assume these TIDs will continue to live (no need to read /proc again), since no logic