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