xref: /netbsd-src/tests/lib/libc/gen/posix_spawn/t_spawnattr.c (revision 63264fc80c92778b2e56b0599e3b7e509e9ad3b6)
1*63264fc8Sandvar /* $NetBSD: t_spawnattr.c,v 1.6 2022/05/23 21:46:12 andvar Exp $ */
20ce98f42Smartin 
30ce98f42Smartin /*-
40ce98f42Smartin  * Copyright (c) 2012 The NetBSD Foundation, Inc.
50ce98f42Smartin  * All rights reserved.
60ce98f42Smartin  *
70ce98f42Smartin  * This code is derived from software contributed to The NetBSD Foundation
80ce98f42Smartin  * by Charles Zhang <charles@NetBSD.org> and
90ce98f42Smartin  * Martin Husemann <martin@NetBSD.org>.
100ce98f42Smartin  *
110ce98f42Smartin  * Redistribution and use in source and binary forms, with or without
120ce98f42Smartin  * modification, are permitted provided that the following conditions
130ce98f42Smartin  * are met:
140ce98f42Smartin  * 1. Redistributions of source code must retain the above copyright
150ce98f42Smartin  *    notice, this list of conditions and the following disclaimer.
160ce98f42Smartin  * 2. Redistributions in binary form must reproduce the above copyright
170ce98f42Smartin  *    notice, this list of conditions and the following disclaimer in the
180ce98f42Smartin  *    documentation and/or other materials provided with the distribution.
190ce98f42Smartin  *
200ce98f42Smartin  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
210ce98f42Smartin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
220ce98f42Smartin  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
230ce98f42Smartin  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
240ce98f42Smartin  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
250ce98f42Smartin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
260ce98f42Smartin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
270ce98f42Smartin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
280ce98f42Smartin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
290ce98f42Smartin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
300ce98f42Smartin  * POSSIBILITY OF SUCH DAMAGE.
310ce98f42Smartin  */
32c0746c1eSchristos #include <sys/cdefs.h>
33*63264fc8Sandvar __RCSID("$NetBSD: t_spawnattr.c,v 1.6 2022/05/23 21:46:12 andvar Exp $");
340ce98f42Smartin 
35c0746c1eSchristos #include <sys/param.h>
360ce98f42Smartin #include <atf-c.h>
370ce98f42Smartin #include <stdio.h>
380ce98f42Smartin #include <stdlib.h>
390ce98f42Smartin #include <string.h>
400ce98f42Smartin #include <errno.h>
410ce98f42Smartin #include <fcntl.h>
420ce98f42Smartin #include <sched.h>
430ce98f42Smartin #include <signal.h>
440ce98f42Smartin #include <spawn.h>
450ce98f42Smartin #include <unistd.h>
460ce98f42Smartin #include <sys/wait.h>
470ce98f42Smartin 
480ce98f42Smartin static int
get_different_scheduler(void)491abf1d78Schristos get_different_scheduler(void)
500ce98f42Smartin {
51a0fb54abSchristos 	/*
52a0fb54abSchristos 	 * We don't want to use SCHED_OTHER because it does not have
53a0fb54abSchristos 	 * different priorities.
54a0fb54abSchristos 	 */
550ce98f42Smartin 
560ce98f42Smartin 	/* get current schedule policy */
57a0fb54abSchristos 	switch (sched_getscheduler(0)) {
58a0fb54abSchristos 	case SCHED_RR:
59a0fb54abSchristos 		return SCHED_FIFO;
60a0fb54abSchristos 	case SCHED_FIFO:
61a0fb54abSchristos 	case SCHED_OTHER:
62a0fb54abSchristos 		return SCHED_RR;
63a0fb54abSchristos 	default:
64a0fb54abSchristos 		abort();
65a0fb54abSchristos 	}
660ce98f42Smartin }
670ce98f42Smartin 
680ce98f42Smartin static int
get_different_priority(int scheduler)691abf1d78Schristos get_different_priority(int scheduler)
700ce98f42Smartin {
711abf1d78Schristos 	int min, max, new, priority;
720ce98f42Smartin 	struct sched_param param;
730ce98f42Smartin 
741abf1d78Schristos 	/* Get the priority range for the new scheduler */
750ce98f42Smartin 	max = sched_get_priority_max(scheduler);
760ce98f42Smartin 	min = sched_get_priority_min(scheduler);
770ce98f42Smartin 
780ce98f42Smartin 	sched_getparam(0, &param);
790ce98f42Smartin 	priority = param.sched_priority;
800ce98f42Smartin 
810ce98f42Smartin 	/* new schedule policy */
821abf1d78Schristos 	for (new = min; new <= max; new++)
831abf1d78Schristos 		if (priority != new)
841abf1d78Schristos 			break;
850ce98f42Smartin 
861abf1d78Schristos 	ATF_REQUIRE_MSG(priority != new, "could not find different priority");
871abf1d78Schristos 	printf("min %d max %d for scheduler %d, returning %d\n",
881abf1d78Schristos 	    min, max, scheduler, new);
890ce98f42Smartin 	return new;
900ce98f42Smartin }
910ce98f42Smartin 
920ce98f42Smartin ATF_TC(t_spawnattr);
930ce98f42Smartin 
ATF_TC_HEAD(t_spawnattr,tc)940ce98f42Smartin ATF_TC_HEAD(t_spawnattr, tc)
950ce98f42Smartin {
960ce98f42Smartin 	atf_tc_set_md_var(tc, "require.user", "root");
970ce98f42Smartin 	atf_tc_set_md_var(tc, "descr",
980ce98f42Smartin 	    "Tests posix_spawn with scheduler attributes");
990ce98f42Smartin }
1000ce98f42Smartin 
ATF_TC_BODY(t_spawnattr,tc)1010ce98f42Smartin ATF_TC_BODY(t_spawnattr, tc)
1020ce98f42Smartin {
1030ce98f42Smartin 	int pid, scheduler, child_scheduler, priority, status, err, pfd[2];
1040ce98f42Smartin 	char helper_arg[128];
1050ce98f42Smartin 	char * const args[] = { __UNCONST("h_spawnattr"), helper_arg, NULL };
1060ce98f42Smartin 	struct sched_param sp, child_sp;
1070ce98f42Smartin 	sigset_t sig;
1080ce98f42Smartin 	posix_spawnattr_t attr;
1090ce98f42Smartin 	char helper[FILENAME_MAX];
1100ce98f42Smartin 
1110ce98f42Smartin 	/*
112*63264fc8Sandvar 	 * create a pipe to control the child
1130ce98f42Smartin 	 */
1140ce98f42Smartin 	err = pipe(pfd);
1150ce98f42Smartin 	ATF_REQUIRE_MSG(err == 0, "could not create pipe, errno %d", errno);
1160ce98f42Smartin 	sprintf(helper_arg, "%d", pfd[0]);
1170ce98f42Smartin 
1180ce98f42Smartin 	posix_spawnattr_init(&attr);
1190ce98f42Smartin 
1200ce98f42Smartin 	scheduler = get_different_scheduler();
1211abf1d78Schristos 	priority = get_different_priority(scheduler);
1220ce98f42Smartin 	sp.sched_priority = priority;
1231abf1d78Schristos 	printf("using scheduler %d, priority %d\n", scheduler, priority);
1240ce98f42Smartin 
1250ce98f42Smartin 	sigemptyset(&sig);
1260ce98f42Smartin 	sigaddset(&sig, SIGUSR1);
1270ce98f42Smartin 
1280ce98f42Smartin 	posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSCHEDULER |
1290ce98f42Smartin 		POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETPGROUP |
1300ce98f42Smartin 		POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
1310ce98f42Smartin 		POSIX_SPAWN_SETSIGDEF);
1320ce98f42Smartin 	posix_spawnattr_setpgroup(&attr, 0);
1330ce98f42Smartin 	posix_spawnattr_setschedparam(&attr, &sp);
1340ce98f42Smartin 	posix_spawnattr_setschedpolicy(&attr, scheduler);
1350ce98f42Smartin 	posix_spawnattr_setsigmask(&attr, &sig);
1360ce98f42Smartin 	posix_spawnattr_setsigdefault(&attr, &sig);
1370ce98f42Smartin 
1380ce98f42Smartin 	sprintf(helper, "%s/h_spawnattr",
1390ce98f42Smartin 	    atf_tc_get_config_var(tc, "srcdir"));
1400ce98f42Smartin 	err = posix_spawn(&pid, helper, NULL, &attr, args, NULL);
1410ce98f42Smartin 	ATF_REQUIRE_MSG(err == 0, "error %d", err);
1420ce98f42Smartin 
1430ce98f42Smartin 	child_scheduler = sched_getscheduler(pid);
1440ce98f42Smartin 	ATF_REQUIRE_MSG(scheduler == child_scheduler,
1450ce98f42Smartin 	    "scheduler = %d, child_scheduler = %d, pid %d, errno %d",
1460ce98f42Smartin 	    scheduler, child_scheduler, pid, errno);
1470ce98f42Smartin 
1480ce98f42Smartin 	sched_getparam(pid, &child_sp);
1490ce98f42Smartin 	ATF_REQUIRE_MSG(child_sp.sched_priority == sp.sched_priority,
1500ce98f42Smartin 	    "priority is: %d, but we requested: %d",
1510ce98f42Smartin 	    child_sp.sched_priority, sp.sched_priority);
1520ce98f42Smartin 
1530ce98f42Smartin 	ATF_REQUIRE_MSG(pid == getpgid(pid), "child pid: %d, child pgid: %d",
1540ce98f42Smartin 	    pid, getpgid(pid));
1550ce98f42Smartin 
1560ce98f42Smartin 	/* ready, let child go */
1570ce98f42Smartin 	write(pfd[1], "q", 1);
1580ce98f42Smartin 	close(pfd[0]);
1590ce98f42Smartin 	close(pfd[1]);
1600ce98f42Smartin 
1610ce98f42Smartin 	/* wait and check result from child */
1620ce98f42Smartin 	waitpid(pid, &status, 0);
1630ce98f42Smartin 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
1640ce98f42Smartin 
1650ce98f42Smartin 	posix_spawnattr_destroy(&attr);
1660ce98f42Smartin }
1670ce98f42Smartin 
1683e0848b4Smartin ATF_TC(t_spawn_resetids);
1693e0848b4Smartin 
ATF_TC_HEAD(t_spawn_resetids,tc)1703e0848b4Smartin ATF_TC_HEAD(t_spawn_resetids, tc)
1713e0848b4Smartin {
1723e0848b4Smartin 	atf_tc_set_md_var(tc, "descr",
1733e0848b4Smartin 	    "posix_spawn a child and with POSIX_SPAWN_RESETIDS flag");
1743e0848b4Smartin }
1753e0848b4Smartin 
ATF_TC_BODY(t_spawn_resetids,tc)1763e0848b4Smartin ATF_TC_BODY(t_spawn_resetids, tc)
1773e0848b4Smartin {
1783e0848b4Smartin 	char buf[FILENAME_MAX];
1793e0848b4Smartin 	char * const args[] = {
1803e0848b4Smartin 	     __UNCONST("h_spawn"), __UNCONST("--resetids"), NULL
1813e0848b4Smartin 	};
1823e0848b4Smartin 	posix_spawnattr_t attr;
1833e0848b4Smartin 	int err, status;
1843e0848b4Smartin 	pid_t pid;
1853e0848b4Smartin 
1863e0848b4Smartin 	posix_spawnattr_init(&attr);
1873e0848b4Smartin 	posix_spawnattr_setflags(&attr, POSIX_SPAWN_RESETIDS);
1883e0848b4Smartin 
1893e0848b4Smartin 	snprintf(buf, sizeof buf, "%s/h_spawn",
1903e0848b4Smartin 	    atf_tc_get_config_var(tc, "srcdir"));
1913e0848b4Smartin 
1923e0848b4Smartin 	err = posix_spawn(&pid, buf, NULL, &attr, args, NULL);
1933e0848b4Smartin 	ATF_REQUIRE(err == 0);
1943e0848b4Smartin 	ATF_REQUIRE(pid > 0);
1953e0848b4Smartin 	waitpid(pid, &status, 0);
1963e0848b4Smartin 	ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
1973e0848b4Smartin 
1983e0848b4Smartin 	posix_spawnattr_destroy(&attr);
1993e0848b4Smartin }
2003e0848b4Smartin 
ATF_TP_ADD_TCS(tp)2010ce98f42Smartin ATF_TP_ADD_TCS(tp)
2020ce98f42Smartin {
2030ce98f42Smartin 	ATF_TP_ADD_TC(tp, t_spawnattr);
2043e0848b4Smartin 	ATF_TP_ADD_TC(tp, t_spawn_resetids);
2050ce98f42Smartin 
2060ce98f42Smartin 	return atf_no_error();
2070ce98f42Smartin }
208