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$
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
4457257Sdufault#include <unistd.h>
4557257Sdufault#include <stdlib.h>
4657257Sdufault
4757257Sdufault#include <stdio.h>
4857257Sdufault#include <string.h>
4957257Sdufault#include <errno.h>
5057257Sdufault#include <fcntl.h>
5157257Sdufault#include <sys/mman.h>
5257257Sdufault
5357257Sdufault#include <sched.h>
5457257Sdufault
5557257Sdufault#include "prutil.h"
5657257Sdufault
5757257Sdufaultstatic FILE *verbose;
5857257Sdufault
5957257Sdufaultstatic void
6057257Sdufaultcheckpris(int sched)
6157257Sdufault{
6257257Sdufault	int smin;
6357257Sdufault	int smax;
6457257Sdufault
6557257Sdufault	errno = 0;
6657257Sdufault
6757257Sdufault	if ( (smin = sched_get_priority_min(sched)) == -1 && errno)
6857257Sdufault		quit("sched_get_priority_min");
6957257Sdufault
7057257Sdufault	if ( (smax = sched_get_priority_max(sched)) == -1 && errno)
7157257Sdufault		quit("sched_get_priority_max");
7257257Sdufault
7357257Sdufault	if (smax - smin + 1 < 32 || smax < smin) {
7457257Sdufault		fprintf(stderr, "Illegal priority range for %s: %d to %d\n",
7557257Sdufault		sched_text(sched), smin, smax);
7657257Sdufault		exit(-1);
7757257Sdufault	}
7857257Sdufault
7957257Sdufault	if (verbose)
8057257Sdufault		fprintf(verbose, "%12s: sched_min %2d sched_max %2d\n",
8157257Sdufault		sched_text(sched), smin, smax);
8257257Sdufault}
8357257Sdufault
8457257Sdufault/* Set "try_anyway" to quit if you don't want to go on when
8557257Sdufault * it doesn't look like something should work.
8657257Sdufault */
8757257Sdufaultstatic void try_anyway(const char *s)
8857257Sdufault{
8957257Sdufault	fputs(s, stderr);
9057257Sdufault	fprintf(stderr, "(trying anyway)\n");
9157257Sdufault	errno = 0;
9257257Sdufault}
9357257Sdufault
9457257Sdufaultstatic void q(int line, int code, const char *text)
9557257Sdufault{
9657257Sdufault	if (code == -1)
9757257Sdufault	{
9857257Sdufault		fprintf(stderr, "Error at line %d:\n", line);
9957257Sdufault		perror(text);
10057257Sdufault		exit(errno);
10157257Sdufault	}
10257257Sdufault}
10357257Sdufault
10457257Sdufaultint sched(int ac, char *av[])
10557257Sdufault{
10657257Sdufault	int fifo_schedmin, fifo_schedmax;
10757257Sdufault	int i;
10857257Sdufault	struct sched_param rt_param;
10957257Sdufault	int n_instances = 10;
11057257Sdufault	int sched;
11157257Sdufault
11257257Sdufault	verbose = 0;
11357257Sdufault
11457257Sdufault#if _POSIX_VERSION < 199309
11557257Sdufault	try_anyway("The _POSIX_VERSION predates P1003.1B\n");
11657257Sdufault#endif
11757257Sdufault
11857257Sdufault#if !defined(_POSIX_PRIORITY_SCHEDULING)
11957257Sdufault	try_anyway(
12057257Sdufault	"The environment does not claim to support Posix scheduling.\n");
12157257Sdufault#endif
12257257Sdufault
12357257Sdufault	/* Is priority scheduling configured?
12457257Sdufault	 */
12557257Sdufault	errno = 0;
12657257Sdufault	if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
12757257Sdufault		if (errno != 0) {
12857257Sdufault			/* This isn't valid - may be a standard violation
12957257Sdufault			 */
13057257Sdufault			quit("(should not happen) sysconf(_SC_PRIORITY_SCHEDULING)");
13157257Sdufault		}
13257257Sdufault		else {
13357257Sdufault			try_anyway(
13457257Sdufault			"The environment does not have run-time "
13557257Sdufault			"support for Posix scheduling.\n");
13657257Sdufault		}
13757257Sdufault	}
13857257Sdufault
13957257Sdufault	/* Check that the priorities seem reasonable.
14057257Sdufault	 */
14157257Sdufault
14257257Sdufault	checkpris(SCHED_FIFO);
14357257Sdufault	checkpris(SCHED_RR);
14457257Sdufault	checkpris(SCHED_OTHER);
14557257Sdufault
14657257Sdufault/* BSD extensions?
14757257Sdufault */
14857257Sdufault#if defined(SCHED_IDLE)
14957257Sdufault	checkpris(SCHED_IDLE);
15057257Sdufault#endif
15157257Sdufault
15257257Sdufault	fifo_schedmin = sched_get_priority_min(SCHED_FIFO);
15357257Sdufault	fifo_schedmax = sched_get_priority_max(SCHED_FIFO);
15457257Sdufault
15557257Sdufault	/* Make sure we can do some basic schedule switching:
15657257Sdufault	 */
15757257Sdufault	{
15857257Sdufault		struct sched_param orig_param, shouldbe;
15957257Sdufault		int orig_scheduler = sched_is(__LINE__, &orig_param, -1);
16057257Sdufault
16157257Sdufault		if (verbose)
16257257Sdufault			fprintf(verbose,
16357257Sdufault			"The original scheduler is %s and the priority is %d.\n",
16457257Sdufault			sched_text(orig_scheduler), orig_param.sched_priority);
16557257Sdufault
16657257Sdufault		/* Basic check: Try to set current settings:
16757257Sdufault		 */
16857257Sdufault		q(__LINE__, sched_setscheduler(0, orig_scheduler, &orig_param),
16957257Sdufault			"sched_setscheduler: Can't set original scheduler");
17057257Sdufault
17157257Sdufault		rt_param.sched_priority = fifo_schedmin;
17257257Sdufault
17357257Sdufault		q(__LINE__, sched_setscheduler(0, SCHED_FIFO, &rt_param),
17457257Sdufault		"sched_setscheduler SCHED_FIFO");
17557257Sdufault
17657257Sdufault		(void)sched_is(__LINE__, 0, SCHED_FIFO);
17757257Sdufault
17857257Sdufault		q(__LINE__, sched_getparam(0, &shouldbe), "sched_getparam");
17957257Sdufault
18057257Sdufault		if (shouldbe.sched_priority != fifo_schedmin)
18157257Sdufault			quit("sched_setscheduler wrong priority (min)");
18257257Sdufault
18357257Sdufault		rt_param.sched_priority = fifo_schedmin;
18457257Sdufault
18557257Sdufault		q(__LINE__, sched_setparam(0, &rt_param),
18657257Sdufault			"sched_setparam to fifo_schedmin");
18757257Sdufault
18857257Sdufault		rt_param.sched_priority = fifo_schedmin + 1;
18957257Sdufault
19057257Sdufault		q(__LINE__, sched_setparam(0, &rt_param),
19157257Sdufault			"sched_setparam to fifo_schedmin + 1");
19257257Sdufault
19357257Sdufault		q(__LINE__, sched_getparam(0, &shouldbe),
19457257Sdufault			"sched_getparam");
19557257Sdufault
19657257Sdufault		if (shouldbe.sched_priority != fifo_schedmin + 1)
19757257Sdufault			quit("sched_setscheduler wrong priority (min + 1)");
19857257Sdufault
19957257Sdufault		q(__LINE__, sched_setscheduler(0, SCHED_RR, &rt_param),
20057257Sdufault			"sched_setscheduler SCHED_RR");
20157257Sdufault
20257257Sdufault		(void)sched_is(__LINE__, 0, SCHED_RR);
20357257Sdufault
20457257Sdufault		q(__LINE__, sched_setscheduler(0, orig_scheduler, &orig_param),
20557257Sdufault			"sched_setscheduler restoring original scheduler");
20657257Sdufault
20757257Sdufault		(void)sched_is(__LINE__, 0, orig_scheduler);
20857257Sdufault	}
20957257Sdufault
21057257Sdufault
21157257Sdufault	{
21257257Sdufault#define NAM "P1003_1b_schedXXXX"
21357257Sdufault		char nam[L_tmpnam];
21457257Sdufault		int fd;
21557257Sdufault		pid_t p;
21657257Sdufault		pid_t *lastrun;
21757257Sdufault
21857257Sdufault		strcpy(nam, NAM);
21957257Sdufault		if (tmpnam(nam) != nam)
22057257Sdufault			q(__LINE__, errno, "tmpnam " NAM);
22157257Sdufault		q(__LINE__, (fd = open(nam, O_RDWR|O_CREAT, 0666)),
22257257Sdufault			"open " NAM);
22357257Sdufault
22457257Sdufault		(void)unlink(nam);
22557257Sdufault
22657257Sdufault		p = (pid_t)0;
22757257Sdufault
22857257Sdufault		write(fd, &p, sizeof(p));
22957257Sdufault
23057257Sdufault		q(__LINE__,  (int)(lastrun = mmap(0, sizeof(*lastrun), PROT_READ|PROT_WRITE,
23157257Sdufault		MAP_SHARED, fd, 0)), "mmap");
23257257Sdufault
23357257Sdufault		/* Set our priority at the highest:
23457257Sdufault		 */
23557257Sdufault		sched = SCHED_FIFO;
23657257Sdufault		rt_param.sched_priority = fifo_schedmax;
23757257Sdufault		q(__LINE__, sched_setscheduler(0, sched, &rt_param),
23857257Sdufault		"sched_setscheduler sched");
23957257Sdufault
24057257Sdufault		for (i = 0; i < n_instances; i++)
24157257Sdufault		{
24257257Sdufault			pid_t me;
24357257Sdufault
24457257Sdufault			/* XXX This is completely bogus.  The children never run.
24557257Sdufault			 */
24657257Sdufault			if ((me = fork()) != 0)
24757257Sdufault			{
24857257Sdufault				/* Parent.
24957257Sdufault				 */
25057257Sdufault				(void)sched_is(__LINE__, 0, sched);
25157257Sdufault
25257257Sdufault				/* Lower our priority:
25357257Sdufault				 */
25457257Sdufault				rt_param.sched_priority--;
25557257Sdufault
25657257Sdufault				q(__LINE__, sched_setscheduler(0, sched, &rt_param),
25757257Sdufault				"sched_setscheduler sched");
25857257Sdufault
25957257Sdufault				while (1)
26057257Sdufault				{
26157257Sdufault					q(__LINE__, sched_getparam(0, &rt_param), "sched_getparam");
26257257Sdufault
26357257Sdufault					rt_param.sched_priority--;
26457257Sdufault
26557257Sdufault
26657257Sdufault					if (rt_param.sched_priority < fifo_schedmin)
26757257Sdufault						exit(0);
26857257Sdufault
26957257Sdufault					*lastrun = me;
27057257Sdufault					q(__LINE__, sched_setparam(0, &rt_param), "sched_setparam");
27157257Sdufault
27257257Sdufault					if (*lastrun == me)
27357257Sdufault					{
27457257Sdufault						/* The child will run twice
27557257Sdufault						 * at  the end:
27657257Sdufault						 */
27757257Sdufault						if (!me || rt_param.sched_priority != 0)
27857257Sdufault						{
27957257Sdufault							fprintf(stderr,
28057257Sdufault							"ran process %ld twice at priority %d\n",
28157257Sdufault							(long)me, rt_param.sched_priority + 1);
28257257Sdufault							exit(-1);
28357257Sdufault						}
28457257Sdufault					}
28557257Sdufault				}
28657257Sdufault			}
28757257Sdufault		}
28857257Sdufault	}
28957257Sdufault
29057257Sdufault	return 0;
29157257Sdufault}
29257257Sdufault#ifdef STANDALONE_TESTS
29357257Sdufaultint main(int argc, char *argv[]) { return sched(argc, argv); }
29457257Sdufault#endif
295