From 162d8bf1682d99e52d005c8febcd18ec201d2706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Guidi?= Date: Mon, 3 Apr 2023 12:10:55 -0400 Subject: [PATCH 1/2] utils: Implement syscall wrappers for glibc < 2.30 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Glibc < 2.30 doen't provide wrappers for 'gettid()' and 'tgkill()' so we define them. Signed-off-by: Clément Guidi --- utils/utils.c | 26 ++++++++++++++++++++++++++ utils/utils.h | 3 +++ 2 files changed, 29 insertions(+) diff --git a/utils/utils.c b/utils/utils.c index cd49bb8da..8e79feba9 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #ifdef HAVE_LIBUNWIND @@ -1032,6 +1033,31 @@ int copy_file(const char *path_in, const char *path_out) return 0; } +#ifndef gettid +/** + * gettid - gettid syscall wrapper (glibc < 2.30) + * @return - thread id + */ +pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#endif + +#ifndef tgkill +/** + * tgkill - tgkill syscall wrapper (glibc < 2.30) + * @tgid - thread group id + * @tid - thread id + * @signal - signal to send + * @return - 0 on success, -1 on error + */ +int tgkill(pid_t tgid, pid_t tid, int signal) +{ + return syscall(SYS_tgkill, tgid, tid, signal); +} +#endif + #ifdef UNIT_TEST TEST_CASE(utils_parse_cmdline) { diff --git a/utils/utils.h b/utils/utils.h index 393def811..08ea94608 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -431,4 +431,7 @@ void stacktrace(void); int copy_file(const char *path_in, const char *path_out); +pid_t gettid(void); +int tgkill(pid_t tgid, pid_t tid, int signal); + #endif /* UFTRACE_UTILS_H */ From 0398ceb4c8d5caab3d69f13c90cb5018faea3872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Guidi?= Date: Tue, 4 Apr 2023 09:30:03 -0400 Subject: [PATCH 2/2] utils: Define signal related functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Functions to setup real-time signals and broadcast signals to all threads in an application. Useful for runtime synchronization mechanisms. Co-authored-by: Gabriel-Andrew Pollo-Guilbert Signed-off-by: Clément Guidi --- utils/utils.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ utils/utils.h | 3 ++ 2 files changed, 93 insertions(+) diff --git a/utils/utils.c b/utils/utils.c index 8e79feba9..7bec63d0a 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -1058,6 +1058,96 @@ int tgkill(pid_t tgid, pid_t tid, int signal) } #endif +/** + * find_unused_sigrt - find a real-time signal with no associated action + * @return - unused RT signal, or -1 if none found + */ +int find_unused_sigrt(void) +{ + int sig; + struct sigaction oldact; + + for (sig = SIGRTMIN; sig <= SIGRTMAX; sig++) { + if (sigaction(sig, NULL, &oldact) < 0) { + pr_dbg3("failed to check RT signal handler\n"); + continue; + } + + if (!oldact.sa_handler) + return sig; + } + + pr_dbg2("failed to find unused SIGRT\n"); + return -1; +} + +/** + * thread_broadcast_signal - send a signal to all the other running threads in + * the process + * @sig - signal to send + * @return - number of signals sent, -1 on error + */ +int thread_broadcast_signal(int sig) +{ + char path[32]; + DIR *dir; + struct dirent *dirent; + pid_t pid, tid, task; + int signal_count = 0; + + pid = getpid(); + tid = gettid(); + + snprintf(path, 32, "/proc/%u/task", pid); + dir = opendir(path); + if (!dir) { + pr_dbg("failed to open directory '%s'\n", path); + goto fail_open_dir; + } + + errno = 0; + for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) { + /* skip "." and ".." directories */ + if (dirent->d_name[0] == '.') + continue; + + task = strtol(dirent->d_name, NULL, 10); + if (errno != 0 || task < 0) { + pr_dbg("failed to parse TID '%s'\n", dirent->d_name); + continue; + } + + /* ignore our TID */ + if (task == tid) + continue; + + /* + * By reading /proc//task directory, there is the possibility of + * a race condition where a thread exits before we send the signal. + */ + pr_dbg4("send SIGRT%d to %u\n", sig, task); + if (tgkill(pid, task, sig) < 0) { + if (errno != ESRCH) { + pr_dbg2("cannot signal thread %u: %s\n", task, strerror(errno)); + errno = 0; + } + } + else + signal_count++; + } + + if (errno != 0) + pr_dbg("failed to read directory entry\n"); + + if (closedir(dir) < 0) + pr_dbg2("failed to close directory\n"); + + return signal_count; + +fail_open_dir: + return -1; +} + #ifdef UNIT_TEST TEST_CASE(utils_parse_cmdline) { diff --git a/utils/utils.h b/utils/utils.h index 08ea94608..9f20bfc97 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -434,4 +434,7 @@ int copy_file(const char *path_in, const char *path_out); pid_t gettid(void); int tgkill(pid_t tgid, pid_t tid, int signal); +int find_unused_sigrt(void); +int thread_broadcast_signal(int sig); + #endif /* UFTRACE_UTILS_H */