157257Sdufault/*
257257Sdufault * Copyright (c) 1996-1999
357257Sdufault *	HD Associates, Inc.  All rights reserved.
457257Sdufault *
557257Sdufault * Redistribution and use in source and binary forms, with or without
657257Sdufault * modification, are permitted provided that the following conditions
757257Sdufault * are met:
857257Sdufault * 1. Redistributions of source code must retain the above copyright
957257Sdufault *    notice, this list of conditions and the following disclaimer.
1057257Sdufault * 2. Redistributions in binary form must reproduce the above copyright
1157257Sdufault *    notice, this list of conditions and the following disclaimer in the
1257257Sdufault *    documentation and/or other materials provided with the distribution.
1357257Sdufault * 3. All advertising materials mentioning features or use of this software
1457257Sdufault *    must display the following acknowledgement:
1557257Sdufault *	This product includes software developed by HD Associates, Inc
1657257Sdufault * 4. Neither the name of the author nor the names of any co-contributors
1757257Sdufault *    may be used to endorse or promote products derived from this software
1857257Sdufault *    without specific prior written permission.
1957257Sdufault *
2057257Sdufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
2157257Sdufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2257257Sdufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2357257Sdufault * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
2457257Sdufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2557257Sdufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2657257Sdufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2757257Sdufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2857257Sdufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2957257Sdufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3057257Sdufault * SUCH DAMAGE.
3157257Sdufault * $FreeBSD: releng/10.3/tools/regression/p1003_1b/sched.c 289954 2015-10-25 22:30:45Z ngie $
3257257Sdufault *
3357257Sdufault */
3457257Sdufault
3557257Sdufault/* XXX: The spec says that if _POSIX_C_SOURCE is defined then
3657257Sdufault *      _POSIX_SOURCE is ignored.  However, this is similar to
3757257Sdufault *      the code in the O'Reilly "POSIX.4" book
3857257Sdufault */
3957257Sdufault
4057257Sdufault#define _POSIX_VERSION 199309L
4157257Sdufault#define _POSIX_SOURCE
4257257Sdufault#define _POSIX_C_SOURCE 199309L
4357257Sdufault
44289954Sngie#include <sys/mman.h>
4557257Sdufault#include <errno.h>
4657257Sdufault#include <fcntl.h>
47289954Sngie#include <limits.h>
4857257Sdufault#include <sched.h>
49289954Sngie#include <stdio.h>
50289954Sngie#define	__XSI_VISIBLE 1
51289954Sngie#include <stdlib.h>
52289954Sngie#undef __XSI_VISIBLE
53289954Sngie#include <string.h>
54289954Sngie#include <unistd.h>
5557257Sdufault
5657257Sdufault#include "prutil.h"
5757257Sdufault
5857257Sdufaultstatic FILE *verbose;
5957257Sdufault
6057257Sdufaultstatic void
6157257Sdufaultcheckpris(int sched)
6257257Sdufault{
6357257Sdufault	int smin;
6457257Sdufault	int smax;
6557257Sdufault
6657257Sdufault	errno = 0;
6757257Sdufault
6857257Sdufault	if ( (smin = sched_get_priority_min(sched)) == -1 && errno)
6957257Sdufault		quit("sched_get_priority_min");
7057257Sdufault
7157257Sdufault	if ( (smax = sched_get_priority_max(sched)) == -1 && errno)
7257257Sdufault		quit("sched_get_priority_max");
7357257Sdufault
7457257Sdufault	if (smax - smin + 1 < 32 || smax < smin) {
7557257Sdufault		fprintf(stderr, "Illegal priority range for %s: %d to %d\n",
7657257Sdufault		sched_text(sched), smin, smax);
7757257Sdufault		exit(-1);
7857257Sdufault	}
7957257Sdufault
8057257Sdufault	if (verbose)
8157257Sdufault		fprintf(verbose, "%12s: sched_min %2d sched_max %2d\n",
8257257Sdufault		sched_text(sched), smin, smax);
8357257Sdufault}
8457257Sdufault
8557257Sdufault/* Set "try_anyway" to quit if you don't want to go on when
8657257Sdufault * it doesn't look like something should work.
8757257Sdufault */
8857257Sdufaultstatic void try_anyway(const char *s)
8957257Sdufault{
9057257Sdufault	fputs(s, stderr);
9157257Sdufault	fprintf(stderr, "(trying anyway)\n");
9257257Sdufault	errno = 0;
9357257Sdufault}
9457257Sdufault
9557257Sdufaultstatic void q(int line, int code, const char *text)
9657257Sdufault{
9757257Sdufault	if (code == -1)
9857257Sdufault	{
9957257Sdufault		fprintf(stderr, "Error at line %d:\n", line);
10057257Sdufault		perror(text);
10157257Sdufault		exit(errno);
10257257Sdufault	}
10357257Sdufault}
10457257Sdufault
10557257Sdufaultint sched(int ac, char *av[])
10657257Sdufault{
10757257Sdufault	int fifo_schedmin, fifo_schedmax;
10857257Sdufault	int i;
10957257Sdufault	struct sched_param rt_param;
11057257Sdufault	int n_instances = 10;
11157257Sdufault	int sched;
11257257Sdufault
11357257Sdufault	verbose = 0;
11457257Sdufault
11557257Sdufault#if _POSIX_VERSION < 199309
11657257Sdufault	try_anyway("The _POSIX_VERSION predates P1003.1B\n");
11757257Sdufault#endif
11857257Sdufault
11957257Sdufault#if !defined(_POSIX_PRIORITY_SCHEDULING)
12057257Sdufault	try_anyway(
12157257Sdufault	"The environment does not claim to support Posix scheduling.\n");
12257257Sdufault#endif
12357257Sdufault
12457257Sdufault	/* Is priority scheduling configured?
12557257Sdufault	 */
12657257Sdufault	errno = 0;
12757257Sdufault	if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
12857257Sdufault		if (errno != 0) {
12957257Sdufault			/* This isn't valid - may be a standard violation
13057257Sdufault			 */
13157257Sdufault			quit("(should not happen) sysconf(_SC_PRIORITY_SCHEDULING)");
13257257Sdufault		}
13357257Sdufault		else {
13457257Sdufault			try_anyway(
13557257Sdufault			"The environment does not have run-time "
13657257Sdufault			"support for Posix scheduling.\n");
13757257Sdufault		}
13857257Sdufault	}
13957257Sdufault
14057257Sdufault	/* Check that the priorities seem reasonable.
14157257Sdufault	 */
14257257Sdufault
14357257Sdufault	checkpris(SCHED_FIFO);
14457257Sdufault	checkpris(SCHED_RR);
14557257Sdufault	checkpris(SCHED_OTHER);
14657257Sdufault
14757257Sdufault/* BSD extensions?
14857257Sdufault */
14957257Sdufault#if defined(SCHED_IDLE)
15057257Sdufault	checkpris(SCHED_IDLE);
15157257Sdufault#endif
15257257Sdufault
15357257Sdufault	fifo_schedmin = sched_get_priority_min(SCHED_FIFO);
15457257Sdufault	fifo_schedmax = sched_get_priority_max(SCHED_FIFO);
15557257Sdufault
15657257Sdufault	/* Make sure we can do some basic schedule switching:
15757257Sdufault	 */
15857257Sdufault	{
15957257Sdufault		struct sched_param orig_param, shouldbe;
16057257Sdufault		int orig_scheduler = sched_is(__LINE__, &orig_param, -1);
16157257Sdufault
16257257Sdufault		if (verbose)
16357257Sdufault			fprintf(verbose,
16457257Sdufault			"The original scheduler is %s and the priority is %d.\n",
16557257Sdufault			sched_text(orig_scheduler), orig_param.sched_priority);
16657257Sdufault
16757257Sdufault		/* Basic check: Try to set current settings:
16857257Sdufault		 */
16957257Sdufault		q(__LINE__, sched_setscheduler(0, orig_scheduler, &orig_param),
17057257Sdufault			"sched_setscheduler: Can't set original scheduler");
17157257Sdufault
17257257Sdufault		rt_param.sched_priority = fifo_schedmin;
17357257Sdufault
17457257Sdufault		q(__LINE__, sched_setscheduler(0, SCHED_FIFO, &rt_param),
17557257Sdufault		"sched_setscheduler SCHED_FIFO");
17657257Sdufault
17757257Sdufault		(void)sched_is(__LINE__, 0, SCHED_FIFO);
17857257Sdufault
17957257Sdufault		q(__LINE__, sched_getparam(0, &shouldbe), "sched_getparam");
18057257Sdufault
18157257Sdufault		if (shouldbe.sched_priority != fifo_schedmin)
18257257Sdufault			quit("sched_setscheduler wrong priority (min)");
18357257Sdufault
18457257Sdufault		rt_param.sched_priority = fifo_schedmin;
18557257Sdufault
18657257Sdufault		q(__LINE__, sched_setparam(0, &rt_param),
18757257Sdufault			"sched_setparam to fifo_schedmin");
18857257Sdufault
18957257Sdufault		rt_param.sched_priority = fifo_schedmin + 1;
19057257Sdufault
19157257Sdufault		q(__LINE__, sched_setparam(0, &rt_param),
19257257Sdufault			"sched_setparam to fifo_schedmin + 1");
19357257Sdufault
19457257Sdufault		q(__LINE__, sched_getparam(0, &shouldbe),
19557257Sdufault			"sched_getparam");
19657257Sdufault
19757257Sdufault		if (shouldbe.sched_priority != fifo_schedmin + 1)
19857257Sdufault			quit("sched_setscheduler wrong priority (min + 1)");
19957257Sdufault
20057257Sdufault		q(__LINE__, sched_setscheduler(0, SCHED_RR, &rt_param),
20157257Sdufault			"sched_setscheduler SCHED_RR");
20257257Sdufault
20357257Sdufault		(void)sched_is(__LINE__, 0, SCHED_RR);
20457257Sdufault
20557257Sdufault		q(__LINE__, sched_setscheduler(0, orig_scheduler, &orig_param),
20657257Sdufault			"sched_setscheduler restoring original scheduler");
20757257Sdufault
20857257Sdufault		(void)sched_is(__LINE__, 0, orig_scheduler);
20957257Sdufault	}
21057257Sdufault
21157257Sdufault
21257257Sdufault	{
213289954Sngie		char nam[] = "P1003_1b_schedXXXXXX";
21457257Sdufault		int fd;
21557257Sdufault		pid_t p;
21657257Sdufault		pid_t *lastrun;
21757257Sdufault
218289954Sngie		fd = mkstemp(nam);
219289954Sngie		if (fd == -1)
220289954Sngie			q(__LINE__, errno, "mkstemp failed");
22157257Sdufault
22257257Sdufault		(void)unlink(nam);
22357257Sdufault
22457257Sdufault		p = (pid_t)0;
22557257Sdufault
22657257Sdufault		write(fd, &p, sizeof(p));
22757257Sdufault
22857257Sdufault		q(__LINE__,  (int)(lastrun = mmap(0, sizeof(*lastrun), PROT_READ|PROT_WRITE,
22957257Sdufault		MAP_SHARED, fd, 0)), "mmap");
23057257Sdufault
23157257Sdufault		/* Set our priority at the highest:
23257257Sdufault		 */
23357257Sdufault		sched = SCHED_FIFO;
23457257Sdufault		rt_param.sched_priority = fifo_schedmax;
23557257Sdufault		q(__LINE__, sched_setscheduler(0, sched, &rt_param),
23657257Sdufault		"sched_setscheduler sched");
23757257Sdufault
23857257Sdufault		for (i = 0; i < n_instances; i++)
23957257Sdufault		{
24057257Sdufault			pid_t me;
24157257Sdufault
24257257Sdufault			/* XXX This is completely bogus.  The children never run.
24357257Sdufault			 */
24457257Sdufault			if ((me = fork()) != 0)
24557257Sdufault			{
24657257Sdufault				/* Parent.
24757257Sdufault				 */
24857257Sdufault				(void)sched_is(__LINE__, 0, sched);
24957257Sdufault
25057257Sdufault				/* Lower our priority:
25157257Sdufault				 */
25257257Sdufault				rt_param.sched_priority--;
25357257Sdufault
25457257Sdufault				q(__LINE__, sched_setscheduler(0, sched, &rt_param),
25557257Sdufault				"sched_setscheduler sched");
25657257Sdufault
25757257Sdufault				while (1)
25857257Sdufault				{
25957257Sdufault					q(__LINE__, sched_getparam(0, &rt_param), "sched_getparam");
26057257Sdufault
26157257Sdufault					rt_param.sched_priority--;
26257257Sdufault
26357257Sdufault
26457257Sdufault					if (rt_param.sched_priority < fifo_schedmin)
26557257Sdufault						exit(0);
26657257Sdufault
26757257Sdufault					*lastrun = me;
26857257Sdufault					q(__LINE__, sched_setparam(0, &rt_param), "sched_setparam");
26957257Sdufault
27057257Sdufault					if (*lastrun == me)
27157257Sdufault					{
27257257Sdufault						/* The child will run twice
27357257Sdufault						 * at  the end:
27457257Sdufault						 */
27557257Sdufault						if (!me || rt_param.sched_priority != 0)
27657257Sdufault						{
27757257Sdufault							fprintf(stderr,
27857257Sdufault							"ran process %ld twice at priority %d\n",
27957257Sdufault							(long)me, rt_param.sched_priority + 1);
28057257Sdufault							exit(-1);
28157257Sdufault						}
28257257Sdufault					}
28357257Sdufault				}
28457257Sdufault			}
28557257Sdufault		}
28657257Sdufault	}
28757257Sdufault
28857257Sdufault	return 0;
28957257Sdufault}
29057257Sdufault#ifdef STANDALONE_TESTS
29157257Sdufaultint main(int argc, char *argv[]) { return sched(argc, argv); }
29257257Sdufault#endif
293