core-process-v5.4
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCXXe8mQAKCRCRxhvAZXjc
ou7oAQCszihkNfpjORSSSOqenMDrxxDW++A7TIOLuq7UyZQl8QD+LM1wvT/xypfJ
ORD9XX8+Wrv07AQn85fZBEFXGrnengk=
=o+VL
-----END PGP SIGNATURE-----
Merge tag 'core-process-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux
Pull pidfd/waitid updates from Christian Brauner:
"This contains two features and various tests.
First, it adds support for waiting on process through pidfds by adding
the P_PIDFD type to the waitid() syscall. This completes the basic
functionality of the pidfd api (cf. [1]). In the meantime we also have
a new adition to the userspace projects that make use of the pidfd
api. The qt project was nice enough to send a mail pointing out that
they have a pr up to switch to the pidfd api (cf. [2]).
Second, this tag contains an extension to the waitid() syscall to make
it possible to wait on the current process group in a race free manner
(even though the actual problem is very unlikely) by specifing 0
together with the P_PGID type. This extension traces back to a
discussion on the glibc development mailing list.
There are also a range of tests for the features above. Additionally,
the test-suite which detected the pidfd-polling race we fixed in [3]
is included in this tag"
[1] https://lwn.net/Articles/794707/
[2] https://codereview.qt-project.org/c/qt/qtbase/+/108456
[3] commit b191d6491b
("pidfd: fix a poll race when setting exit_state")
* tag 'core-process-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
waitid: Add support for waiting for the current process group
tests: add pidfd poll tests
tests: move common definitions and functions into pidfd.h
pidfd: add pidfd_wait tests
pidfd: add P_PIDFD to waitid()
This commit is contained in:
commit
c17112a5c4
|
@ -72,6 +72,10 @@ extern struct pid init_struct_pid;
|
||||||
|
|
||||||
extern const struct file_operations pidfd_fops;
|
extern const struct file_operations pidfd_fops;
|
||||||
|
|
||||||
|
struct file;
|
||||||
|
|
||||||
|
extern struct pid *pidfd_pid(const struct file *file);
|
||||||
|
|
||||||
static inline struct pid *get_pid(struct pid *pid)
|
static inline struct pid *get_pid(struct pid *pid)
|
||||||
{
|
{
|
||||||
if (pid)
|
if (pid)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#define P_ALL 0
|
#define P_ALL 0
|
||||||
#define P_PID 1
|
#define P_PID 1
|
||||||
#define P_PGID 2
|
#define P_PGID 2
|
||||||
|
#define P_PIDFD 3
|
||||||
|
|
||||||
|
|
||||||
#endif /* _UAPI_LINUX_WAIT_H */
|
#endif /* _UAPI_LINUX_WAIT_H */
|
||||||
|
|
|
@ -1554,6 +1554,23 @@ end:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct pid *pidfd_get_pid(unsigned int fd)
|
||||||
|
{
|
||||||
|
struct fd f;
|
||||||
|
struct pid *pid;
|
||||||
|
|
||||||
|
f = fdget(fd);
|
||||||
|
if (!f.file)
|
||||||
|
return ERR_PTR(-EBADF);
|
||||||
|
|
||||||
|
pid = pidfd_pid(f.file);
|
||||||
|
if (!IS_ERR(pid))
|
||||||
|
get_pid(pid);
|
||||||
|
|
||||||
|
fdput(f);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
||||||
int options, struct rusage *ru)
|
int options, struct rusage *ru)
|
||||||
{
|
{
|
||||||
|
@ -1576,19 +1593,32 @@ static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop,
|
||||||
type = PIDTYPE_PID;
|
type = PIDTYPE_PID;
|
||||||
if (upid <= 0)
|
if (upid <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
pid = find_get_pid(upid);
|
||||||
break;
|
break;
|
||||||
case P_PGID:
|
case P_PGID:
|
||||||
type = PIDTYPE_PGID;
|
type = PIDTYPE_PGID;
|
||||||
if (upid <= 0)
|
if (upid < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (upid)
|
||||||
|
pid = find_get_pid(upid);
|
||||||
|
else
|
||||||
|
pid = get_task_pid(current, PIDTYPE_PGID);
|
||||||
|
break;
|
||||||
|
case P_PIDFD:
|
||||||
|
type = PIDTYPE_PID;
|
||||||
|
if (upid < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pid = pidfd_get_pid(upid);
|
||||||
|
if (IS_ERR(pid))
|
||||||
|
return PTR_ERR(pid);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type < PIDTYPE_MAX)
|
|
||||||
pid = find_get_pid(upid);
|
|
||||||
|
|
||||||
wo.wo_type = type;
|
wo.wo_type = type;
|
||||||
wo.wo_pid = pid;
|
wo.wo_pid = pid;
|
||||||
wo.wo_flags = options;
|
wo.wo_flags = options;
|
||||||
|
|
|
@ -1690,6 +1690,14 @@ static inline void rcu_copy_process(struct task_struct *p)
|
||||||
#endif /* #ifdef CONFIG_TASKS_RCU */
|
#endif /* #ifdef CONFIG_TASKS_RCU */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pid *pidfd_pid(const struct file *file)
|
||||||
|
{
|
||||||
|
if (file->f_op == &pidfd_fops)
|
||||||
|
return file->private_data;
|
||||||
|
|
||||||
|
return ERR_PTR(-EBADF);
|
||||||
|
}
|
||||||
|
|
||||||
static int pidfd_release(struct inode *inode, struct file *file)
|
static int pidfd_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct pid *pid = file->private_data;
|
struct pid *pid = file->private_data;
|
||||||
|
|
|
@ -3678,8 +3678,11 @@ static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
|
||||||
|
|
||||||
static struct pid *pidfd_to_pid(const struct file *file)
|
static struct pid *pidfd_to_pid(const struct file *file)
|
||||||
{
|
{
|
||||||
if (file->f_op == &pidfd_fops)
|
struct pid *pid;
|
||||||
return file->private_data;
|
|
||||||
|
pid = pidfd_pid(file);
|
||||||
|
if (!IS_ERR(pid))
|
||||||
|
return pid;
|
||||||
|
|
||||||
return tgid_pidfd_to_pid(file);
|
return tgid_pidfd_to_pid(file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
pidfd_open_test
|
pidfd_open_test
|
||||||
|
pidfd_poll_test
|
||||||
pidfd_test
|
pidfd_test
|
||||||
|
pidfd_wait
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
CFLAGS += -g -I../../../../usr/include/ -lpthread
|
CFLAGS += -g -I../../../../usr/include/ -lpthread
|
||||||
|
|
||||||
TEST_GEN_PROGS := pidfd_test pidfd_open_test
|
TEST_GEN_PROGS := pidfd_test pidfd_open_test pidfd_poll_test pidfd_wait
|
||||||
|
|
||||||
include ../lib.mk
|
include ../lib.mk
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,26 @@
|
||||||
|
|
||||||
#include "../kselftest.h"
|
#include "../kselftest.h"
|
||||||
|
|
||||||
|
#ifndef P_PIDFD
|
||||||
|
#define P_PIDFD 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLONE_PIDFD
|
||||||
|
#define CLONE_PIDFD 0x00001000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __NR_pidfd_open
|
||||||
|
#define __NR_pidfd_open -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __NR_pidfd_send_signal
|
||||||
|
#define __NR_pidfd_send_signal -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __NR_clone3
|
||||||
|
#define __NR_clone3 -1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
|
* The kernel reserves 300 pids via RESERVED_PIDS in kernel/pid.c
|
||||||
* That means, when it wraps around any pid < 300 will be skipped.
|
* That means, when it wraps around any pid < 300 will be skipped.
|
||||||
|
@ -53,5 +73,15 @@ again:
|
||||||
return WEXITSTATUS(status);
|
return WEXITSTATUS(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_pidfd_open, pid, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __PIDFD_H */
|
#endif /* __PIDFD_H */
|
||||||
|
|
|
@ -22,11 +22,6 @@
|
||||||
#include "pidfd.h"
|
#include "pidfd.h"
|
||||||
#include "../kselftest.h"
|
#include "../kselftest.h"
|
||||||
|
|
||||||
static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
|
|
||||||
{
|
|
||||||
return syscall(__NR_pidfd_open, pid, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int safe_int(const char *numstr, int *converted)
|
static int safe_int(const char *numstr, int *converted)
|
||||||
{
|
{
|
||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pidfd.h"
|
||||||
|
#include "../kselftest.h"
|
||||||
|
|
||||||
|
static bool timeout;
|
||||||
|
|
||||||
|
static void handle_alarm(int sig)
|
||||||
|
{
|
||||||
|
timeout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct pollfd fds;
|
||||||
|
int iter, nevents;
|
||||||
|
int nr_iterations = 10000;
|
||||||
|
|
||||||
|
fds.events = POLLIN;
|
||||||
|
|
||||||
|
if (argc > 2)
|
||||||
|
ksft_exit_fail_msg("Unexpected command line argument\n");
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
nr_iterations = atoi(argv[1]);
|
||||||
|
if (nr_iterations <= 0)
|
||||||
|
ksft_exit_fail_msg("invalid input parameter %s\n",
|
||||||
|
argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ksft_print_msg("running pidfd poll test for %d iterations\n",
|
||||||
|
nr_iterations);
|
||||||
|
|
||||||
|
for (iter = 0; iter < nr_iterations; iter++) {
|
||||||
|
int pidfd;
|
||||||
|
int child_pid = fork();
|
||||||
|
|
||||||
|
if (child_pid < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
iter--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s - failed to fork a child process\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_pid == 0) {
|
||||||
|
/* Child process just sleeps for a min and exits */
|
||||||
|
sleep(60);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parent kills the child and waits for its death */
|
||||||
|
pidfd = sys_pidfd_open(child_pid, 0);
|
||||||
|
if (pidfd < 0)
|
||||||
|
ksft_exit_fail_msg("%s - pidfd_open failed\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
/* Setup 3 sec alarm - plenty of time */
|
||||||
|
if (signal(SIGALRM, handle_alarm) == SIG_ERR)
|
||||||
|
ksft_exit_fail_msg("%s - signal failed\n",
|
||||||
|
strerror(errno));
|
||||||
|
alarm(3);
|
||||||
|
|
||||||
|
/* Send SIGKILL to the child */
|
||||||
|
if (sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0))
|
||||||
|
ksft_exit_fail_msg("%s - pidfd_send_signal failed\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
/* Wait for the death notification */
|
||||||
|
fds.fd = pidfd;
|
||||||
|
nevents = poll(&fds, 1, -1);
|
||||||
|
|
||||||
|
/* Check for error conditions */
|
||||||
|
if (nevents < 0)
|
||||||
|
ksft_exit_fail_msg("%s - poll failed\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (nevents != 1)
|
||||||
|
ksft_exit_fail_msg("unexpected poll result: %d\n",
|
||||||
|
nevents);
|
||||||
|
|
||||||
|
if (!(fds.revents & POLLIN))
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"unexpected event type received: 0x%x\n",
|
||||||
|
fds.revents);
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"death notification wait timeout\n");
|
||||||
|
|
||||||
|
close(pidfd);
|
||||||
|
/* Wait for child to prevent zombies */
|
||||||
|
if (waitpid(child_pid, NULL, 0) < 0)
|
||||||
|
ksft_exit_fail_msg("%s - waitpid failed\n",
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ksft_test_result_pass("pidfd poll test: pass\n");
|
||||||
|
return ksft_exit_pass();
|
||||||
|
}
|
|
@ -21,20 +21,12 @@
|
||||||
#include "pidfd.h"
|
#include "pidfd.h"
|
||||||
#include "../kselftest.h"
|
#include "../kselftest.h"
|
||||||
|
|
||||||
#ifndef __NR_pidfd_send_signal
|
|
||||||
#define __NR_pidfd_send_signal -1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define str(s) _str(s)
|
#define str(s) _str(s)
|
||||||
#define _str(s) #s
|
#define _str(s) #s
|
||||||
#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
|
#define CHILD_THREAD_MIN_WAIT 3 /* seconds */
|
||||||
|
|
||||||
#define MAX_EVENTS 5
|
#define MAX_EVENTS 5
|
||||||
|
|
||||||
#ifndef CLONE_PIDFD
|
|
||||||
#define CLONE_PIDFD 0x00001000
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
|
static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
|
||||||
{
|
{
|
||||||
size_t stack_size = 1024;
|
size_t stack_size = 1024;
|
||||||
|
@ -47,12 +39,6 @@ static pid_t pidfd_clone(int flags, int *pidfd, int (*fn)(void *))
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int sys_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int signal_received;
|
static int signal_received;
|
||||||
|
|
||||||
static void set_signal_received_on_sigusr1(int sig)
|
static void set_signal_received_on_sigusr1(int sig)
|
||||||
|
|
|
@ -0,0 +1,271 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <errno.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pidfd.h"
|
||||||
|
#include "../kselftest.h"
|
||||||
|
|
||||||
|
#define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr)))
|
||||||
|
|
||||||
|
static pid_t sys_clone3(struct clone_args *args)
|
||||||
|
{
|
||||||
|
return syscall(__NR_clone3, args, sizeof(struct clone_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sys_waitid(int which, pid_t pid, siginfo_t *info, int options,
|
||||||
|
struct rusage *ru)
|
||||||
|
{
|
||||||
|
return syscall(__NR_waitid, which, pid, info, options, ru);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_pidfd_wait_simple(void)
|
||||||
|
{
|
||||||
|
const char *test_name = "pidfd wait simple";
|
||||||
|
int pidfd = -1, status = 0;
|
||||||
|
pid_t parent_tid = -1;
|
||||||
|
struct clone_args args = {
|
||||||
|
.parent_tid = ptr_to_u64(&parent_tid),
|
||||||
|
.pidfd = ptr_to_u64(&pidfd),
|
||||||
|
.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
|
||||||
|
.exit_signal = SIGCHLD,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
pid_t pid;
|
||||||
|
siginfo_t info = {
|
||||||
|
.si_signo = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pidfd = open("/proc/self", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
|
||||||
|
if (pidfd < 0)
|
||||||
|
ksft_exit_fail_msg("%s test: failed to open /proc/self %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
|
||||||
|
pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||||
|
if (pid == 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: succeeded to wait on invalid pidfd %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
close(pidfd);
|
||||||
|
pidfd = -1;
|
||||||
|
|
||||||
|
pidfd = open("/dev/null", O_RDONLY | O_CLOEXEC);
|
||||||
|
if (pidfd == 0)
|
||||||
|
ksft_exit_fail_msg("%s test: failed to open /dev/null %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
|
||||||
|
pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||||
|
if (pid == 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: succeeded to wait on invalid pidfd %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
close(pidfd);
|
||||||
|
pidfd = -1;
|
||||||
|
|
||||||
|
pid = sys_clone3(&args);
|
||||||
|
if (pid < 0)
|
||||||
|
ksft_exit_fail_msg("%s test: failed to create new process %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
pid = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||||
|
if (pid < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to wait on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
if (!WIFEXITED(info.si_status) || WEXITSTATUS(info.si_status))
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected status received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
close(pidfd);
|
||||||
|
|
||||||
|
if (info.si_signo != SIGCHLD)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_signo, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_code != CLD_EXITED)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_code, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_pid != parent_tid)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_pid, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
ksft_test_result_pass("%s test: Passed\n", test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_pidfd_wait_states(void)
|
||||||
|
{
|
||||||
|
const char *test_name = "pidfd wait states";
|
||||||
|
int pidfd = -1, status = 0;
|
||||||
|
pid_t parent_tid = -1;
|
||||||
|
struct clone_args args = {
|
||||||
|
.parent_tid = ptr_to_u64(&parent_tid),
|
||||||
|
.pidfd = ptr_to_u64(&pidfd),
|
||||||
|
.flags = CLONE_PIDFD | CLONE_PARENT_SETTID,
|
||||||
|
.exit_signal = SIGCHLD,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
pid_t pid;
|
||||||
|
siginfo_t info = {
|
||||||
|
.si_signo = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pid = sys_clone3(&args);
|
||||||
|
if (pid < 0)
|
||||||
|
ksft_exit_fail_msg("%s test: failed to create new process %s\n",
|
||||||
|
test_name, strerror(errno));
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
kill(getpid(), SIGSTOP);
|
||||||
|
kill(getpid(), SIGSTOP);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sys_waitid(P_PIDFD, pidfd, &info, WSTOPPED, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to wait on WSTOPPED process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_signo != SIGCHLD)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_signo, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_code != CLD_STOPPED)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_code, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_pid != parent_tid)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_pid, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to send signal to process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
ret = sys_waitid(P_PIDFD, pidfd, &info, WCONTINUED, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to wait WCONTINUED on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_signo != SIGCHLD)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_signo, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_code != CLD_CONTINUED)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_code, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_pid != parent_tid)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_pid, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
ret = sys_waitid(P_PIDFD, pidfd, &info, WUNTRACED, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to wait on WUNTRACED process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_signo != SIGCHLD)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_signo, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_code != CLD_STOPPED)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_code, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_pid != parent_tid)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_pid, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to send SIGKILL to process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
ret = sys_waitid(P_PIDFD, pidfd, &info, WEXITED, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: failed to wait on WEXITED process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, parent_tid, pidfd, strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_signo != SIGCHLD)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_signo value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_signo, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_code != CLD_KILLED)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_code value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_code, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (info.si_pid != parent_tid)
|
||||||
|
ksft_exit_fail_msg(
|
||||||
|
"%s test: unexpected si_pid value %d received after waiting on process with pid %d and pidfd %d: %s\n",
|
||||||
|
test_name, info.si_pid, parent_tid, pidfd,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
close(pidfd);
|
||||||
|
|
||||||
|
ksft_test_result_pass("%s test: Passed\n", test_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
ksft_print_header();
|
||||||
|
ksft_set_plan(2);
|
||||||
|
|
||||||
|
test_pidfd_wait_simple();
|
||||||
|
test_pidfd_wait_states();
|
||||||
|
|
||||||
|
return ksft_exit_pass();
|
||||||
|
}
|
Loading…
Reference in New Issue