1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 */
6
7 /*
8 * Description:
9 * Set CPU time limit for a process and check its behavior
10 * after reaching CPU time limit.
11 * 1) Process got SIGXCPU after reaching soft limit of CPU time.
12 * 2) Process got SIGKILL after reaching hard limit of CPU time.
13 *
14 * Note:
15 * This is also a regression test for the following kernel bug:
16 * 'c3bca5d450b62 ("posix-cpu-timers: Ensure set_process_cpu_timer is always evaluated")'
17 */
18
19 #define _GNU_SOURCE
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 #include <sys/wait.h>
26 #include <stdlib.h>
27 #include <sys/mman.h>
28
29 #include "tst_test.h"
30
31 static int *end;
32
sighandler(int sig)33 static void sighandler(int sig)
34 {
35 *end = sig;
36 }
37
setup(void)38 static void setup(void)
39 {
40 SAFE_SIGNAL(SIGXCPU, sighandler);
41
42 end = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE,
43 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
44 }
45
cleanup(void)46 static void cleanup(void)
47 {
48 if (end)
49 SAFE_MUNMAP(end, sizeof(int));
50 }
51
verify_setrlimit(void)52 static void verify_setrlimit(void)
53 {
54 int status;
55 pid_t pid;
56
57 *end = 0;
58
59 pid = SAFE_FORK();
60 if (!pid) {
61 struct rlimit rlim = {
62 .rlim_cur = 2,
63 .rlim_max = 3,
64 };
65
66 TEST(setrlimit(RLIMIT_CPU, &rlim));
67 if (TST_RET == -1) {
68 tst_res(TFAIL | TTERRNO,
69 "setrlimit(RLIMIT_CPU) failed");
70 exit(1);
71 }
72
73 alarm(10);
74
75 while (1);
76 }
77
78 SAFE_WAITPID(pid, &status, 0);
79
80 if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
81 return;
82
83 if (WIFSIGNALED(status)) {
84 if (WTERMSIG(status) == SIGKILL && *end == SIGXCPU) {
85 tst_res(TPASS,
86 "Got SIGXCPU then SIGKILL after reaching both limit");
87 return;
88 }
89
90 if (WTERMSIG(status) == SIGKILL && !*end) {
91 tst_res(TFAIL,
92 "Got only SIGKILL after reaching both limit");
93 return;
94 }
95
96 if (WTERMSIG(status) == SIGALRM && *end == SIGXCPU) {
97 tst_res(TFAIL,
98 "Got only SIGXCPU after reaching both limit");
99 return;
100 }
101
102 if (WTERMSIG(status) == SIGALRM && !*end) {
103 tst_res(TFAIL,
104 "Got no signal after reaching both limit");
105 return;
106 }
107 }
108
109 tst_res(TBROK, "Child %s", tst_strstatus(status));
110 }
111
112 static struct tst_test test = {
113 .test_all = verify_setrlimit,
114 .setup = setup,
115 .cleanup = cleanup,
116 .forks_child = 1,
117 .tags = (const struct tst_tag[]) {
118 {"linux-git", "c3bca5d450b62"},
119 {}
120 }
121 };
122