process-util: add helper get_process_threads()
Let's add a proper helper for querying the number of threads in a process.
This commit is contained in:
+1
-3
@@ -277,7 +277,6 @@ static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX
|
||||
#if VALGRIND
|
||||
_destructor_ static void cleanup_pools(void) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
/* Be nice to valgrind */
|
||||
|
||||
@@ -291,8 +290,7 @@ _destructor_ static void cleanup_pools(void) {
|
||||
if (getpid() != gettid())
|
||||
return;
|
||||
|
||||
r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
|
||||
if (r < 0 || !streq(t, "1"))
|
||||
if (get_process_threads(0) != 1)
|
||||
return;
|
||||
|
||||
mempool_drop(&hashmap_pool);
|
||||
|
||||
@@ -1549,6 +1549,31 @@ _noreturn_ void freeze(void) {
|
||||
pause();
|
||||
}
|
||||
|
||||
int get_process_threads(pid_t pid) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
const char *p;
|
||||
int n, r;
|
||||
|
||||
if (pid < 0)
|
||||
return -EINVAL;
|
||||
|
||||
p = procfs_file_alloca(pid, "status");
|
||||
|
||||
r = get_proc_field(p, "Threads", WHITESPACE, &t);
|
||||
if (r == -ENOENT)
|
||||
return proc_mounted() == 0 ? -ENOSYS : -ESRCH;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = safe_atoi(t, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (n < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static const char *const sigchld_code_table[] = {
|
||||
[CLD_EXITED] = "exited",
|
||||
[CLD_KILLED] = "killed",
|
||||
|
||||
@@ -189,3 +189,5 @@ int pidfd_verify_pid(int pidfd, pid_t pid);
|
||||
int setpriority_closest(int priority);
|
||||
|
||||
_noreturn_ void freeze(void);
|
||||
|
||||
int get_process_threads(pid_t pid);
|
||||
|
||||
@@ -310,7 +310,9 @@ tests += [
|
||||
|
||||
[files('test-hostname-util.c')],
|
||||
|
||||
[files('test-process-util.c')],
|
||||
[files('test-process-util.c'),
|
||||
[],
|
||||
[threads]],
|
||||
|
||||
[files('test-terminal-util.c')],
|
||||
|
||||
|
||||
@@ -337,14 +337,10 @@ TEST(executable_is_script) {
|
||||
}
|
||||
|
||||
TEST(status_field) {
|
||||
_cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL;
|
||||
_cleanup_free_ char *p = NULL, *s = NULL, *z = NULL;
|
||||
unsigned long long total = 0, buffers = 0;
|
||||
int r;
|
||||
|
||||
assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
|
||||
puts(t);
|
||||
assert_se(streq(t, "1"));
|
||||
|
||||
r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
|
||||
if (r != -ENOENT) {
|
||||
assert_se(r == 0);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/oom.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/personality.h>
|
||||
#include <sys/prctl.h>
|
||||
@@ -793,6 +794,59 @@ TEST(set_oom_score_adjust) {
|
||||
assert_se(b == a);
|
||||
}
|
||||
|
||||
static void* dummy_thread(void *p) {
|
||||
int fd = PTR_TO_FD(p);
|
||||
char x;
|
||||
|
||||
/* let main thread know we are ready */
|
||||
assert_se(write(fd, &(const char) { 'x' }, 1) == 1);
|
||||
|
||||
/* wait for the main thread to tell us to shut down */
|
||||
assert_se(read(fd, &x, 1) == 1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST(get_process_threads) {
|
||||
int r;
|
||||
|
||||
/* Run this test in a child, so that we can guarantee there's exactly one thread around in the child */
|
||||
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_REOPEN_LOG|FORK_WAIT|FORK_LOG, NULL);
|
||||
assert_se(r >= 0);
|
||||
|
||||
if (r == 0) {
|
||||
_cleanup_close_pair_ int pfd[2] = PIPE_EBADF, ppfd[2] = PIPE_EBADF;
|
||||
pthread_t t, tt;
|
||||
char x;
|
||||
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd) >= 0);
|
||||
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd) >= 0);
|
||||
|
||||
assert_se(get_process_threads(0) == 1);
|
||||
assert_se(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])) == 0);
|
||||
assert_se(read(pfd[1], &x, 1) == 1);
|
||||
assert_se(get_process_threads(0) == 2);
|
||||
assert_se(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])) == 0);
|
||||
assert_se(read(ppfd[1], &x, 1) == 1);
|
||||
assert_se(get_process_threads(0) == 3);
|
||||
|
||||
assert_se(write(pfd[1], &(const char) { 'x' }, 1) == 1);
|
||||
assert_se(pthread_join(t, NULL) == 0);
|
||||
|
||||
/* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
|
||||
* way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
|
||||
* like to check here */
|
||||
assert_se(get_process_threads(0) >= 2);
|
||||
|
||||
assert_se(write(ppfd[1], &(const char) { 'x' }, 1) == 1);
|
||||
assert_se(pthread_join(tt, NULL) == 0);
|
||||
|
||||
/* similar here */
|
||||
assert_se(get_process_threads(0) >= 1);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
static int intro(void) {
|
||||
log_show_color(true);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user