1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved.
4 * Author: Yang Xu <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Verify that the PIDFD_NONBLOCK flag works with pidfd_open() and
11 * that waitid() with a non-blocking pidfd returns EAGAIN.
12 */
13
14 #include <unistd.h>
15 #include <sys/wait.h>
16 #include <stdlib.h>
17 #include "tst_test.h"
18 #include "lapi/pidfd.h"
19
20 #ifndef P_PIDFD
21 #define P_PIDFD 3
22 #endif
23
24 static int pidfd = -1;
25
run(void)26 static void run(void)
27 {
28 int flag, pid, ret;
29 siginfo_t info;
30
31 pid = SAFE_FORK();
32 if (!pid) {
33 TST_CHECKPOINT_WAIT(0);
34 exit(EXIT_SUCCESS);
35 }
36
37 TST_EXP_FD_SILENT(pidfd_open(pid, PIDFD_NONBLOCK),
38 "pidfd_open(%d, PIDFD_NONBLOCK)", pid);
39
40 pidfd = TST_RET;
41 flag = SAFE_FCNTL(pidfd, F_GETFL);
42
43 if (!(flag & O_NONBLOCK))
44 tst_brk(TFAIL, "pidfd_open(%d, O_NONBLOCK) didn't set O_NONBLOCK flag", pid);
45
46 tst_res(TPASS, "pidfd_open(%d, O_NONBLOCK) sets O_NONBLOCK flag", pid);
47
48 TST_EXP_FAIL(waitid(P_PIDFD, pidfd, &info, WEXITED), EAGAIN,
49 "waitid(P_PIDFD,...,WEXITED)");
50
51 TST_CHECKPOINT_WAKE(0);
52
53 ret = TST_RETRY_FUNC(waitid(P_PIDFD, pidfd, &info, WEXITED), TST_RETVAL_EQ0);
54 if (ret == 0) {
55 tst_res(TPASS, "waitid(P_PIDFD) succeeded after child process terminated");
56 } else {
57 tst_res(TFAIL, "waitid(P_PIDFD) failed after child process terminated");
58 SAFE_WAIT(NULL);
59 }
60
61 SAFE_CLOSE(pidfd);
62 }
63
setup(void)64 static void setup(void)
65 {
66 pidfd_open_supported();
67
68 TEST(pidfd_open(getpid(), PIDFD_NONBLOCK));
69 if (TST_RET == -1) {
70 if (TST_ERR == EINVAL) {
71 tst_brk(TCONF, "PIDFD_NONBLOCK was supported since linux 5.10");
72 return;
73 }
74 tst_brk(TFAIL | TTERRNO,
75 "pidfd_open(getpid(),PIDFD_NONBLOCK) failed unexpectedly");
76 }
77 SAFE_CLOSE(TST_RET);
78 }
79
cleanup(void)80 static void cleanup(void)
81 {
82 if (pidfd > -1)
83 SAFE_CLOSE(pidfd);
84 }
85
86 static struct tst_test test = {
87 .needs_root = 1,
88 .forks_child = 1,
89 .needs_checkpoints = 1,
90 .setup = setup,
91 .cleanup = cleanup,
92 .test_all = run,
93 };
94