122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
 | |
|  * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Description:
 | |
|  * Set CPU time limit for a process and check its behavior
 | |
|  * after reaching CPU time limit.
 | |
|  * 1) Process got SIGXCPU after reaching soft limit of CPU time.
 | |
|  * 2) Process got SIGKILL after reaching hard limit of CPU time.
 | |
|  *
 | |
|  * Note:
 | |
|  * This is also a regression test for the following kernel bug:
 | |
|  * 'c3bca5d450b62 ("posix-cpu-timers: Ensure set_process_cpu_timer is always evaluated")'
 | |
|  */
 | |
| 
 | |
| #define _GNU_SOURCE
 | |
| #include <errno.h>
 | |
| #include <sys/types.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/time.h>
 | |
| #include <sys/resource.h>
 | |
| #include <sys/wait.h>
 | |
| #include <stdlib.h>
 | |
| #include <sys/mman.h>
 | |
| 
 | |
| #include "tst_test.h"
 | |
| 
 | |
| static int *end;
 | |
| 
 | |
| static void sighandler(int sig)
 | |
| {
 | |
| 	*end = sig;
 | |
| }
 | |
| 
 | |
| static void setup(void)
 | |
| {
 | |
| 	SAFE_SIGNAL(SIGXCPU, sighandler);
 | |
| 
 | |
| 	end = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE,
 | |
| 			MAP_SHARED | MAP_ANONYMOUS, -1, 0);
 | |
| }
 | |
| 
 | |
| static void cleanup(void)
 | |
| {
 | |
| 	if (end)
 | |
| 		SAFE_MUNMAP(end, sizeof(int));
 | |
| }
 | |
| 
 | |
| static void verify_setrlimit(void)
 | |
| {
 | |
| 	int status;
 | |
| 	pid_t pid;
 | |
| 
 | |
| 	*end = 0;
 | |
| 
 | |
| 	pid = SAFE_FORK();
 | |
| 	if (!pid) {
 | |
| 		struct rlimit rlim = {
 | |
| 			.rlim_cur = 1,
 | |
| 			.rlim_max = 2,
 | |
| 		};
 | |
| 
 | |
| 		TEST(setrlimit(RLIMIT_CPU, &rlim));
 | |
| 		if (TST_RET == -1) {
 | |
| 			tst_res(TFAIL | TTERRNO,
 | |
| 				"setrlimit(RLIMIT_CPU) failed");
 | |
| 			exit(1);
 | |
| 		}
 | |
| 
 | |
| 		alarm(20);
 | |
| 
 | |
| 		while (1);
 | |
| 	}
 | |
| 
 | |
| 	SAFE_WAITPID(pid, &status, 0);
 | |
| 
 | |
| 	if (WIFEXITED(status) && WEXITSTATUS(status) == 1)
 | |
| 		return;
 | |
| 
 | |
| 	if (WIFSIGNALED(status)) {
 | |
| 		if (WTERMSIG(status) == SIGKILL && *end == SIGXCPU) {
 | |
| 			tst_res(TPASS,
 | |
| 				"Got SIGXCPU then SIGKILL after reaching both limit");
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (WTERMSIG(status) == SIGKILL && !*end) {
 | |
| 			tst_res(TFAIL,
 | |
| 				"Got only SIGKILL after reaching both limit");
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (WTERMSIG(status) == SIGALRM && *end == SIGXCPU) {
 | |
| 			tst_res(TFAIL,
 | |
| 				"Got only SIGXCPU after reaching both limit");
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (WTERMSIG(status) == SIGALRM && !*end) {
 | |
| 			tst_res(TFAIL,
 | |
| 				"Got no signal after reaching both limit");
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	tst_res(TFAIL, "Child %s", tst_strstatus(status));
 | |
| }
 | |
| 
 | |
| static struct tst_test test = {
 | |
| 	.test_all = verify_setrlimit,
 | |
| 	.setup = setup,
 | |
| 	.cleanup = cleanup,
 | |
| 	.forks_child = 1,
 | |
| 	.tags = (const struct tst_tag[]) {
 | |
| 		{"linux-git", "c3bca5d450b62"},
 | |
| 		{}
 | |
| 	}
 | |
| };
 |