diff options
| author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
|---|---|---|
| committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
| commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
| tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/dispadmin | |
| download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz | |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/dispadmin')
| -rw-r--r-- | usr/src/cmd/dispadmin/Makefile | 110 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/dispadmin.c | 400 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/dispadmin.h | 73 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/fssdispadmin.c | 279 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/fxdispadmin.c | 356 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/iadispadmin.c | 430 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/rtdispadmin.c | 384 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/subr.c | 255 | ||||
| -rw-r--r-- | usr/src/cmd/dispadmin/tsdispadmin.c | 426 |
9 files changed, 2713 insertions, 0 deletions
diff --git a/usr/src/cmd/dispadmin/Makefile b/usr/src/cmd/dispadmin/Makefile new file mode 100644 index 0000000000..14c2d88cff --- /dev/null +++ b/usr/src/cmd/dispadmin/Makefile @@ -0,0 +1,110 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# cmd/dispadmin/Makefile +# + +PROG= dispadmin +RT= RT$(PROG) +TS= TS$(PROG) +IA= IA$(PROG) +FSS= FSS$(PROG) +FX= FX$(PROG) +PROGS= $(PROG) $(RT) $(TS) $(IA) $(FSS) $(FX) + +include ../Makefile.cmd + +CFLAGS += $(CCVERBOSE) + +ROOTDIR= $(ROOT)/usr/lib/class +ROOTDIRS= $(ROOTDIR) \ + $(ROOTDIR)/RT \ + $(ROOTDIR)/TS \ + $(ROOTDIR)/IA \ + $(ROOTDIR)/FSS \ + $(ROOTDIR)/FX +ROOTPROG= $(PROG:%=$(ROOTUSRSBIN)/%) +ROOTRT= $(RT:%=$(ROOTDIR)/RT/%) +ROOTTS= $(TS:%=$(ROOTDIR)/TS/%) +ROOTIA= $(IA:%=$(ROOTDIR)/IA/%) +ROOTFSS= $(FSS:%=$(ROOTDIR)/FSS/%) +ROOTFX= $(FX:%=$(ROOTDIR)/FX/%) + +GROUP = bin + +# this would be simpler if we renamed rtdispadmin.c and tsdispadmin.c +OBJECTS= $(PROG).o rt$(PROG).o ts$(PROG).o ia$(PROG).o \ + fss$(PROG).o fx$(PROG).o subr.o + +# conditional assignments, because of above names +$(PROG):= OBJ= $(PROG).o +$(RT):= OBJ= rt$(PROG).o +$(TS):= OBJ= ts$(PROG).o +$(IA):= OBJ= ia$(PROG).o +$(FSS):= OBJ= fss$(PROG).o +$(FX):= OBJ= fx$(PROG).o + +# install rules +$(ROOTDIR)/% \ +$(ROOTDIR)/RT/% \ +$(ROOTDIR)/IA/% \ +$(ROOTDIR)/TS/% \ +$(ROOTDIR)/FSS/% \ +$(ROOTDIR)/FX/% : % + $(INS.file) + +.KEEP_STATE: + +all: $(PROGS) + +$(PROGS): $$(OBJ) subr.o + $(LINK.c) -o $@ $(OBJ) subr.o $(LDLIBS) + $(POST_PROCESS) + +llib-lsubr.ln: subr.c + $(LINT.c) -y -o subr subr.c + +lint := LDLIBS += -L. -lsubr + +install: all $(ROOTPROG) $(ROOTRT) $(ROOTTS) $(ROOTIA) $(ROOTFSS) $(ROOTFX) + +# Don't re-install directories already installed by Targetdirs +#$(ROOTDIRS): +# $(INS.dir) + +clean: + $(RM) $(OBJECTS) $(PROGS) llib-lsubr.ln + +lint: llib-lsubr.ln + $(LINT.c) dispadmin.c $(LDLIBS) + $(LINT.c) rtdispadmin.c $(LDLIBS) + $(LINT.c) tsdispadmin.c $(LDLIBS) + $(LINT.c) iadispadmin.c $(LDLIBS) + $(LINT.c) fssdispadmin.c $(LDLIBS) + $(LINT.c) fxdispadmin.c $(LDLIBS) + +include ../Makefile.targ diff --git a/usr/src/cmd/dispadmin/dispadmin.c b/usr/src/cmd/dispadmin/dispadmin.c new file mode 100644 index 0000000000..1a8d3503b2 --- /dev/null +++ b/usr/src/cmd/dispadmin/dispadmin.c @@ -0,0 +1,400 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <limits.h> +#include <wait.h> +#include <zone.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/priocntl.h> + +#include "dispadmin.h" + +/* + * This file contains the code implementing the class independent part + * of the dispadmin command. Most of the functionality of the dispadmin + * command is provided by the class specific sub-commands, the code for + * which is elsewhere. The class independent part of the command is + * responsible for switching out to the appropriate class specific + * sub-command based on the user supplied class argument. + * Code in this file should never assume any knowledge of any specific + * scheduler class (other than the SYS class). + */ + +#define BASENMSZ 16 +#define BUFSZ (PATH_MAX + 80) +#define CLASSPATH "/usr/lib/class" +#define CONFIGPATH "/etc/dispadmin.conf" +#define CONFIGOWNER 0 /* uid 0 (root) */ +#define CONFIGGROUP 1 /* gid 1 (other) */ +#define CONFIGPERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /* 0644 */ +#define TOKENNAME "DEFAULT_SCHEDULER" + +extern char *basename(); + +static char usage[] = +"usage: dispadmin -l\n\ + dispadmin -c class [class-specific options]\n\ + dispadmin -d [class]\n\ + dispadmin -u\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[PATH_MAX]; + +static void print_classlist(); +static void exec_cscmd(char *, char **); +static void set_scheduler(char *); +static void class_info(pcinfo_t *); +static void set_default_class(); + +int +main(int argc, char **argv) +{ + extern char *optarg; + extern int optind, opterr; + + int c; + int uflag, cflag, dflag, lflag, csoptsflag; + char *clname; + + (void) strncpy(cmdpath, argv[0], PATH_MAX); + (void) strncpy(basenm, basename(argv[0]), BASENMSZ); + cflag = dflag = lflag = uflag = csoptsflag = 0; + opterr = 0; + while ((c = getopt(argc, argv, "c:dlu")) != -1) { + switch (c) { + + case 'c': + cflag++; + clname = optarg; + break; + + case 'd': + dflag++; + clname = argv[optind]; + break; + + case 'l': + lflag++; + break; + + case 'u': + uflag++; + break; + + + case '?': + /* + * We assume for now that any option that + * getopt() doesn't recognize is intended for a + * class specific subcommand. + */ + csoptsflag++; + if (argv[optind] && argv[optind][0] != '-') { + + + /* + * Class specific option takes an + * argument which we skip over for now. + */ + optind++; + } + break; + + default: + break; + } + } + + if (lflag) { + if (uflag || cflag || dflag || csoptsflag) + fatalerr(usage); + + print_classlist(); + exit(0); + + } else if (uflag) { + if (lflag || dflag || csoptsflag) + fatalerr(usage); + + set_default_class(); + } else if (cflag) { + if (lflag || dflag) + fatalerr(usage); + + exec_cscmd(clname, argv); + + } else if (dflag) { + if (cflag || lflag || csoptsflag) + fatalerr(usage); + set_scheduler(clname); + exit(0); + + } else { + fatalerr(usage); + } + return (1); +} + + +/* + * Print the heading for the class list and execute the + * class specific sub-command with the -l option for each + * configured class. + */ +static void +print_classlist() +{ + id_t cid; + int nclass; + pcinfo_t pcinfo; + + if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1) + fatalerr("%s: Can't get number of configured classes\n", + cmdpath); + + (void) printf("CONFIGURED CLASSES\n==================\n\n"); + (void) printf("SYS\t(System Class)\n"); + (void) fflush(stdout); + for (cid = 1; cid < nclass; cid++) { + pcinfo.pc_cid = cid; + if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get class name (class ID = %d)\n", + cmdpath, cid); + class_info(&pcinfo); + } +} + + +/* + * Execute the appropriate class specific sub-command for the class + * specified by clname, passing it the arguments in subcmdargv. + */ +static void +exec_cscmd(char *clname, char **subcmdargv) +{ + pcinfo_t pcinfo; + char subcmdpath[PATH_MAX]; + + /* + * Do a quick check to make sure clname is valid. + * We could just wait and see if the exec below + * succeeds but we wouldn't know much about the reason. + * This way we can give the user a more meaningful error + * message. + */ + (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath, + clname); + + (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH, + clname, clname, basenm); + subcmdargv[0] = subcmdpath; + + (void) execv(subcmdpath, subcmdargv); + fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname); +} + +static void +class_info(pcinfo_t *pcinfo) +{ + int pid; + char subcmdpath[PATH_MAX]; + + (void) snprintf(subcmdpath, PATH_MAX, "%s/%s/%s%s", CLASSPATH, + pcinfo->pc_clname, pcinfo->pc_clname, basenm); + if ((pid = fork()) == 0) { + (void) execl(subcmdpath, subcmdpath, "-l", (char *)0); + fatalerr("%s\n\tCan't execute %s specific subcommand\n", + pcinfo->pc_clname, pcinfo->pc_clname); + } else if (pid == (pid_t)-1) { + (void) fprintf(stderr, + "%s\nCan't execute %s specific subcommand)\n", + pcinfo->pc_clname, pcinfo->pc_clname); + } else { + (void) wait(NULL); + } +} + +/* + * Return the current default scheduling class as specified in + * /etc/dispadmin.conf. + */ +static char * +read_default_file(FILE *fp) +{ + char buf[BUFSZ]; + int line; + + for (line = 1; fgets(buf, BUFSZ, fp) != NULL; line++) { + char name[BUFSZ], value[BUFSZ]; + int len; + + if (buf[0] == '#' || buf[0] == '\n') + continue; + /* LINTED - unbounded string specifier */ + if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 && + name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) { + + if (strcmp(name, TOKENNAME) != 0) + fatalerr("\"%s\", line %d: invalid " + "token: %s\n", CONFIGPATH, line, name); + + (void) fclose(fp); + return (strdup(value)); + } else { + fatalerr("\"%s\", line %d: syntax error\n", CONFIGPATH, + line); + (void) fclose(fp); + } + } + if (line == 1) + fatalerr("%s: %s is empty\n", cmdpath, CONFIGPATH); + return (NULL); +} + +/* + * Set the default scheduling class for the system. + * Update /etc/dispadmin.conf if necessary. + */ +static void +set_scheduler(char *clname) +{ + pcinfo_t pcinfo; + FILE *fp; + int fd; + + if (getzoneid() != GLOBAL_ZONEID) + fatalerr("%s: Operation not supported in non-global zones\n", + cmdpath); + + if (clname == NULL) { + if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) { + if (errno == ENOENT) + fatalerr("%s: Default scheduling class " + "is not set\n", cmdpath); + else + fatalerr("%s: Failed to open %s (%s)\n", + cmdpath, CONFIGPATH, strerror(errno)); + } + + if ((fp = fdopen(fd, "r")) == NULL) + fatalerr("%s: Failed to open stream for %s (%s)\n", + cmdpath, CONFIGPATH, strerror(errno)); + clname = read_default_file(fp); + (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ); + + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("\"%s\", scheduling class %s is not " + "available\n", CONFIGPATH, clname); + else + class_info(&pcinfo); + return; + } + + /* + * Do a quick check to make sure clname is valid class name. + */ + (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Invalid or unconfigured class %s\n", cmdpath, + clname); + if ((fd = open(CONFIGPATH, O_RDWR | O_CREAT, CONFIGPERM)) == -1) + fatalerr("%s: Failed to open %s (%s)\n", cmdpath, CONFIGPATH, + strerror(errno)); + if ((fp = fdopen(fd, "w")) == NULL) + fatalerr("%s: Failed to open stream for %s\n", CONFIGPATH); + if (ftruncate(fd, (off_t)0) == -1) + fatalerr("%s: Failed to truncate %s\n", cmdpath, CONFIGPATH); + (void) fputs("#\n# /etc/dispadmin.conf\n#\n" + "# Do NOT edit this file by hand -- use dispadmin(1m) instead.\n" + "#\n", fp); + if ((fprintf(fp, "%s=%s\n", TOKENNAME, clname)) == -1) + fatalerr("%s: Failed to write to %s\n", cmdpath, CONFIGPATH); + if (fflush(fp) != 0) + (void) fprintf(stderr, + "%s: warning: failed to flush config file\n", + cmdpath); + if (fsync(fd) == -1) + (void) fprintf(stderr, + "%s: warning: failed to sync config file to disk\n", + cmdpath); + if (fchmod(fd, CONFIGPERM) == -1) + (void) fprintf(stderr, + "%s: warning: failed to reset config file mode\n", + cmdpath); + if (fchown(fd, CONFIGOWNER, CONFIGGROUP) == -1) + (void) fprintf(stderr, + "%s: warning: failed to reset config file owner\n", + cmdpath); + (void) fclose(fp); + + if (priocntl(0, 0, PC_SETDFLCL, clname) == -1) + fatalerr("%s: failed to set default class %s in kernel: %s\n", + cmdpath, clname, strerror(errno)); +} + +static void +set_default_class() +{ + char *clname; + FILE *fp; + int fd; + + if ((fd = open(CONFIGPATH, O_RDONLY, CONFIGPERM)) == -1) { + /* silently succeed, there is nothing to do */ + if (errno == ENOENT) + return; + else + fatalerr("%s: Failed to open %s (%s)\n", + cmdpath, CONFIGPATH, strerror(errno)); + } + + if ((fp = fdopen(fd, "r")) == NULL) + fatalerr("%s: Failed to open stream for %s (%s)\n", + cmdpath, CONFIGPATH, strerror(errno)); + + if ((clname = read_default_file(fp)) != NULL) { + if (priocntl(0, 0, PC_SETDFLCL, clname) == -1) + fatalerr("%s: failed to set default class %s in " + "kernel: %s\n", cmdpath, clname, strerror(errno)); + } +} diff --git a/usr/src/cmd/dispadmin/dispadmin.h b/usr/src/cmd/dispadmin/dispadmin.h new file mode 100644 index 0000000000..6c54aebaf8 --- /dev/null +++ b/usr/src/cmd/dispadmin/dispadmin.h @@ -0,0 +1,73 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Note that this file does not exist in the SVr4 base, but + * is largely derived from sys/hrtcntl.h, hence the AT&T + * copyright is propagated. SVr4.0 1.9 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * The following is an excerpt from <sys/hrtcntl.h>. HRT timers are not + * supported by SunOS (which will support the POSIX definition). Dispadmin + * uses the hrt routine _hrtnewres because it coincidentally does the + * right thing. These defines allow this routine to be locally included + * in dispadmin (rather than exported in libc). This should be improved in + * the long term. + */ + +/* + * Definitions for specifying rounding mode. + */ + +#define HRT_TRUNC 0 /* Round results down. */ +#define HRT_RND 1 /* Round results (rnd up if fractional */ + /* part >= .5 otherwise round down). */ +#define HRT_RNDUP 2 /* Always round results up. */ + +/* + * Structure used to represent a high-resolution time-of-day + * or interval. + */ + +typedef struct hrtimer { + ulong_t hrt_secs; /* Seconds. */ + long hrt_rem; /* A value less than a second. */ + ulong_t hrt_res; /* The resolution of hrt_rem. */ +} hrtimer_t; + +/* + * Functions in subr.c + */ +extern void fatalerr(const char *, ...); +extern long hrtconvert(hrtimer_t *); +extern int _hrtnewres(hrtimer_t *, ulong_t, long); diff --git a/usr/src/cmd/dispadmin/fssdispadmin.c b/usr/src/cmd/dispadmin/fssdispadmin.c new file mode 100644 index 0000000000..0a404bec62 --- /dev/null +++ b/usr/src/cmd/dispadmin/fssdispadmin.c @@ -0,0 +1,279 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/fss.h> +#include <sys/priocntl.h> +#include <sys/fsspriocntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include "dispadmin.h" + +/* + * This file contains the class specific code implementing the fair-share + * scheduler dispadmin sub-command. + */ + +#define BASENMSZ 16 + +extern char *basename(); +static void getadmin(), setadmin(); + +static char usage[] = "usage: dispadmin -l\n" + "dispadmin -c FSS -g [-r res]\n" + "dispadmin -c FSS -s infile\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[256]; + +int +main(int argc, char **argv) +{ + int c; + int lflag, gflag, rflag, sflag; + ulong_t res; + char *infile; + char *endp; + + (void) strcpy(cmdpath, argv[0]); + (void) strcpy(basenm, basename(argv[0])); + lflag = gflag = rflag = sflag = 0; + while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { + switch (c) { + + case 'l': + lflag++; + break; + + case 'c': + if (strcmp(optarg, "FSS") != 0) + fatalerr("error: %s executed for %s class, " + "%s is actually sub-command for FSS " + "class\n", cmdpath, optarg, cmdpath); + break; + + case 'g': + gflag++; + break; + + case 'r': + rflag++; + errno = 0; + res = strtoul(optarg, &endp, 10); + if (res == 0 || errno != 0 || *endp != '\0') + fatalerr("%s: Can't convert to requested " + "resolution\n", basenm); + break; + + case 's': + sflag++; + infile = optarg; + break; + + case '?': + fatalerr(usage); + + default: + break; + } + } + + if (lflag) { + if (gflag || rflag || sflag) + fatalerr(usage); + + (void) printf("FSS\t(Fair Share)\n"); + return (0); + + } else if (gflag) { + if (lflag || sflag) + fatalerr(usage); + + if (rflag == 0) + res = 1000; + + getadmin(res); + return (0); + + } else if (sflag) { + if (lflag || gflag || rflag) + fatalerr(usage); + + setadmin(infile); + return (0); + + } else { + fatalerr(usage); + } + return (1); +} + +/* + * Retrieve the current settings from kernel, convert the time quantum + * value to the resolution specified by res and print out the results. + */ +static void +getadmin(ulong_t res) +{ + pcinfo_t pcinfo; + pcadmin_t pcadmin; + fssadmin_t fssadmin; + hrtimer_t hrtime; + long fss_quantum; + + (void) strcpy(pcinfo.pc_clname, "FSS"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get FSS class ID, priocntl system call " + "failed (%s)\n", basenm, strerror(errno)); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&fssadmin; + fssadmin.fss_cmd = FSS_GETADMIN; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get scheduler configuration, priocntl " + "system call failed (%s)\n", basenm, strerror(errno)); + + hrtime.hrt_secs = 0; + hrtime.hrt_rem = fssadmin.fss_quantum; + hrtime.hrt_res = HZ; + if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert to requested resolution\n", basenm); + if ((fss_quantum = hrtconvert(&hrtime)) == -1) + fatalerr("%s: Can't express time quantum in " + "requested resolution,\n" + "try coarser resolution\n", basenm); + + (void) printf("#\n# Fair Share Scheduler Configuration\n#\n"); + (void) printf("RES=%ld\n", res); + (void) printf("#\n# Time Quantum\n#\n"); + (void) printf("QUANTUM=%ld\n", fss_quantum); +} + +/* + * Read the scheduler settings from infile, convert the time quantum values + * to HZ resolution, do a little sanity checking and overwrite kernel settings + * with the values from the file. + */ +static void +setadmin(char *infile) +{ + int i; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + fssadmin_t fssadmin; + int line; + ulong_t res; + long fss_quantum; + hrtimer_t hrtime; + FILE *fp; + char buf[512]; + char *endp; + int nparams = 0; + + (void) strcpy(pcinfo.pc_clname, "FSS"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get FSS class ID, priocntl system call " + "failed (%s)\n", basenm, strerror(errno)); + + if ((fp = fopen(infile, "r")) == NULL) + fatalerr("%s: Can't open %s for input\n", basenm, infile); + + for (line = 1; fgets(buf, sizeof (buf), fp) != NULL; line++) { + char name[512], value[512]; + int len; + + if (buf[0] == '#' || buf[0] == '\n') + continue; + /* + * Look for "name=value", with optional whitespaces on either + * side, terminated by a newline, and consuming the whole line. + */ + /* LINTED - unbounded string specifier */ + if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 && + name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) { + + if (strcmp(name, "RES") == 0) { + errno = 0; + i = (int)strtol(value, &endp, 10); + if (errno != 0 || endp == value || + i < 0 || *endp != '\0') + fatalerr("%s, line %d: illegal " + "resolution value\n", infile, line); + else + res = i; + nparams++; + } else if (strcmp(name, "QUANTUM") == 0) { + errno = 0; + i = (int)strtol(value, &endp, 10); + if (errno != 0 || endp == value || + i < 0 || *endp != '\0') + fatalerr("%s, line %d: illegal time " + "quantum value\n", infile, line); + else + fss_quantum = i; + nparams++; + } else { + fatalerr("%s, line %d: invalid token\n", + infile, line); + } + } else { + fatalerr("%s, line %d: syntax error\n", infile, line); + } + } + if (line == 1 || nparams < 2) + fatalerr("cannot read settings from %s\n", infile); + if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = fss_quantum; + hrtime.hrt_res = res; + if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert specified " + "resolution to ticks\n", basenm); + if ((fssadmin.fss_quantum = hrtconvert(&hrtime)) == -1) + fatalerr("%s, line %d: time quantum value out of " + "valid range\n", infile, line); + } else { + fssadmin.fss_quantum = (short)fss_quantum; + } + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&fssadmin; + fssadmin.fss_cmd = FSS_SETADMIN; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't set scheduler parameters, priocntl " + "system call failed (%s)\n", basenm, strerror(errno)); +} diff --git a/usr/src/cmd/dispadmin/fxdispadmin.c b/usr/src/cmd/dispadmin/fxdispadmin.c new file mode 100644 index 0000000000..62d85e829d --- /dev/null +++ b/usr/src/cmd/dispadmin/fxdispadmin.c @@ -0,0 +1,356 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/priocntl.h> +#include <sys/fxpriocntl.h> +#include <sys/param.h> +#include <errno.h> +#include <sys/fx.h> + +#include "dispadmin.h" + +/* + * This file contains the class specific code implementing + * the fixed-priority dispadmin sub-command. + */ + +#define BASENMSZ 16 + +extern char *basename(); + +static void get_fxdptbl(), set_fxdptbl(); + +static char usage[] = "usage: dispadmin -l\n" + "dispadmin -c FX -g [-r res]\n" + "dispadmin -c FX -s infile\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[256]; + + +int +main(int argc, char **argv) +{ + int c; + int lflag, gflag, rflag, sflag; + ulong_t res; + char *infile; + char *endp; + + (void) strcpy(cmdpath, argv[0]); + (void) strcpy(basenm, basename(argv[0])); + lflag = gflag = rflag = sflag = 0; + while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { + switch (c) { + + case 'l': + lflag++; + break; + + case 'c': + if (strcmp(optarg, "FX") != 0) + fatalerr("error: %s executed for %s class, " + "%s is actually sub-command for FX class\n", + cmdpath, optarg, cmdpath); + break; + + case 'g': + gflag++; + break; + + case 'r': + rflag++; + errno = 0; + res = strtoul(optarg, &endp, 10); + if (res == 0 || errno != 0 || *endp != '\0') + fatalerr("%s: Can't convert to requested " + "resolution\n", basenm); + break; + + case 's': + sflag++; + infile = optarg; + break; + + case '?': + fatalerr(usage); + + default: + break; + } + } + + + if (lflag) { + if (gflag || rflag || sflag) + fatalerr(usage); + + (void) printf("FX\t(Fixed Priority)\n"); + return (0); + + } else if (gflag) { + if (sflag) + fatalerr(usage); + + if (rflag == 0) + res = 1000; + + get_fxdptbl(res); + return (0); + + } else if (sflag) { + if (rflag) + fatalerr(usage); + + set_fxdptbl(infile); + return (0); + + } else { + fatalerr(usage); + } + return (1); +} + + +/* + * Retrieve the current fx_dptbl from memory, convert the time quantum + * values to the resolution specified by res and write the table to stdout. + */ +static void +get_fxdptbl(ulong_t res) +{ + int i; + int fxdpsz; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + fxadmin_t fxadmin; + fxdpent_t *fx_dptbl; + hrtimer_t hrtime; + + (void) strcpy(pcinfo.pc_clname, "FX"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get FX class ID, priocntl system call " + "failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&fxadmin; + fxadmin.fx_cmd = FX_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get fx_dptbl size, priocntl system call " + "failed with errno %d\n", basenm, errno); + + fxdpsz = fxadmin.fx_ndpents * sizeof (fxdpent_t); + if ((fx_dptbl = (fxdpent_t *)malloc(fxdpsz)) == NULL) + fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm); + + fxadmin.fx_dpents = fx_dptbl; + + fxadmin.fx_cmd = FX_GETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get fx_dptbl, priocntl system call " + "failed with errno %d\n", basenm, errno); + + (void) printf("# Fixed Priority Dispatcher Configuration\n"); + (void) printf("RES=%ld\n\n", res); + (void) printf("# TIME QUANTUM PRIORITY\n"); + (void) printf("# (fx_quantum) LEVEL\n"); + + for (i = 0; i < fxadmin.fx_ndpents; i++) { + if (res != HZ && fx_dptbl[i].fx_quantum != FX_TQINF) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = fx_dptbl[i].fx_quantum; + hrtime.hrt_res = HZ; + if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert to requested " + "resolution\n", basenm); + if ((fx_dptbl[i].fx_quantum = hrtconvert(&hrtime)) + == -1) + fatalerr("%s: Can't express time quantum in " + "requested resolution,\n" + "try coarser resolution\n", basenm); + } + (void) printf("%10d # %3d\n", + fx_dptbl[i].fx_quantum, i); + } +} + + +/* + * Read the fx_dptbl values from infile, convert the time quantum values + * to HZ resolution, do a little sanity checking and overwrite the table + * in memory with the values from the file. + */ +static void +set_fxdptbl(char *infile) +{ + int i; + int nfxdpents; + char *tokp; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + fxadmin_t fxadmin; + fxdpent_t *fx_dptbl; + int linenum; + ulong_t res; + hrtimer_t hrtime; + FILE *fp; + char buf[512]; + int wslength; + char *endp; + char name[512], value[512]; + int len; + + (void) strcpy(pcinfo.pc_clname, "FX"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get FX class ID, priocntl system call " + "failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&fxadmin; + fxadmin.fx_cmd = FX_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get fx_dptbl size, priocntl system call " + "failed with errno %d\n", basenm, errno); + + nfxdpents = fxadmin.fx_ndpents; + if ((fx_dptbl = + (fxdpent_t *)malloc(nfxdpents * sizeof (fxdpent_t))) == NULL) + fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm); + + if ((fp = fopen(infile, "r")) == NULL) + fatalerr("%s: Can't open %s for input\n", basenm, infile); + + linenum = 0; + + /* + * Find the first non-blank, non-comment line. A comment line + * is any line with '#' as the first non-white-space character. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + /* LINTED - unbounded string specifier */ + if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 && + name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) { + + if (strcmp(name, "RES") == 0) { + errno = 0; + i = (int)strtol(value, &endp, 10); + if (errno != 0 || endp == value || + i < 0 || *endp != '\0') + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + else + res = i; + } else { + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + } + } + + /* + * The remainder of the input file should contain exactly enough + * non-blank, non-comment lines to fill the table (fx_ndpents lines). + * We assume that any non-blank, non-comment line is data for the + * table and fail if we find more or less than we need. + */ + for (i = 0; i < fxadmin.fx_ndpents; i++) { + + /* + * Get the next non-blank, non-comment line. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", + basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + + fx_dptbl[i].fx_quantum = atol(tokp); + if (fx_dptbl[i].fx_quantum <= 0) { + fatalerr("%s: fx_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", basenm, linenum); + } else if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = fx_dptbl[i].fx_quantum; + hrtime.hrt_res = res; + if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert specified " + "resolution to ticks\n", basenm); + if ((fx_dptbl[i].fx_quantum = + hrtconvert(&hrtime)) == -1) + fatalerr("%s: fx_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", basenm, linenum); + } + + if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') + fatalerr("%s: Too many values, line %d of input file\n", + basenm, linenum); + } + + /* + * We've read enough lines to fill the table. We fail + * if the input file contains any more. + */ + while (fgets(buf, sizeof (buf), fp) != NULL) { + if (buf[0] != '#' && buf[0] != '\0' && + (wslength = strspn(buf, " \t\n")) != strlen(buf) && + strchr(buf, '#') != buf + wslength) + fatalerr("%s: Too many lines in input table\n", + basenm); + } + + fxadmin.fx_dpents = fx_dptbl; + fxadmin.fx_cmd = FX_SETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't set fx_dptbl, priocntl system call failed " + "with errno %d\n", basenm, errno); +} diff --git a/usr/src/cmd/dispadmin/iadispadmin.c b/usr/src/cmd/dispadmin/iadispadmin.c new file mode 100644 index 0000000000..aa0b39d05f --- /dev/null +++ b/usr/src/cmd/dispadmin/iadispadmin.c @@ -0,0 +1,430 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/priocntl.h> +#include <sys/iapriocntl.h> +#include <sys/param.h> +#include <sys/ia.h> + +#include "dispadmin.h" + +/* + * This file contains the class specific code implementing + * the interactive dispadmin sub-command. + */ + +#define BASENMSZ 16 + +extern char *basename(); + +static void get_iadptbl(), set_iadptbl(); + +static char usage[] = +"usage: dispadmin -l\n\ + dispadmin -c IA -g [-r res]\n\ + dispadmin -c IA -s infile\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[256]; + + +int +main(int argc, char **argv) +{ + extern char *optarg; + + int c; + int lflag, gflag, rflag, sflag; + ulong_t res; + char *infile; + + (void) strcpy(cmdpath, argv[0]); + (void) strcpy(basenm, basename(argv[0])); + lflag = gflag = rflag = sflag = 0; + while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { + switch (c) { + + case 'l': + lflag++; + break; + + case 'c': + if (strcmp(optarg, "IA") != 0) + fatalerr("error: %s executed for %s class, " + "%s is actually sub-command for IA class\n", + cmdpath, optarg, cmdpath); + break; + + case 'g': + gflag++; + break; + + case 'r': + rflag++; + res = strtoul(optarg, (char **)NULL, 10); + break; + + case 's': + sflag++; + infile = optarg; + break; + + case '?': + fatalerr(usage); + + default: + break; + } + } + + if (lflag) { + if (gflag || rflag || sflag) + fatalerr(usage); + + (void) printf("IA\t(Interactive)\n"); + return (0); + + } else if (gflag) { + if (lflag || sflag) + fatalerr(usage); + + if (rflag == 0) + res = 1000; + + get_iadptbl(res); + return (0); + + } else if (sflag) { + if (lflag || gflag || rflag) + fatalerr(usage); + + set_iadptbl(infile); + return (0); + + } else { + fatalerr(usage); + } + return (1); +} + + +/* + * Retrieve the current ia_dptbl from memory, convert the time quantum + * values to the resolution specified by res and write the table to stdout. + */ +static void +get_iadptbl(ulong_t res) +{ + int i; + int iadpsz; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + iaadmin_t iaadmin; + iadpent_t *ia_dptbl; + hrtimer_t hrtime; + + (void) strcpy(pcinfo.pc_clname, "IA"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get IA class ID, priocntl system " + "call failed with errno %d\n", + basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&iaadmin; + iaadmin.ia_cmd = IA_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ia_dptbl size, priocntl system " + "call failed with errno %d\n", + basenm, errno); + + iadpsz = iaadmin.ia_ndpents * sizeof (iadpent_t); + if ((ia_dptbl = (iadpent_t *)malloc(iadpsz)) == NULL) + fatalerr("%s: Can't allocate memory for ia_dptbl\n", basenm); + + iaadmin.ia_dpents = ia_dptbl; + + iaadmin.ia_cmd = IA_GETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ia_dptbl, priocntl system call " + "call failed with errno %d\n", + basenm, errno); + + (void) printf("# Interactive Dispatcher Configuration\n"); + (void) printf("RES=%ld\n\n", res); + (void) printf("# ia_quantum ia_tqexp ia_slpret ia_maxwait ia_lwait \ +PRIORITY LEVEL\n"); + + for (i = 0; i < iaadmin.ia_ndpents; i++) { + if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = ia_dptbl[i].ia_quantum; + hrtime.hrt_res = HZ; + if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert to requested " + "resolution\n", basenm); + if ((ia_dptbl[i].ia_quantum = hrtconvert(&hrtime)) + == -1) + fatalerr("%s: Can't express time quantum in " + "requested resolution,\n" + "try coarser resolution\n", + basenm); + } + (void) printf("%10ld%10d%10d%12d%10d # %3d\n", + ia_dptbl[i].ia_quantum, ia_dptbl[i].ia_tqexp, + ia_dptbl[i].ia_slpret, ia_dptbl[i].ia_maxwait, + ia_dptbl[i].ia_lwait, i); + } +} + + +/* + * Read the ia_dptbl values from infile, convert the time quantum values + * to HZ resolution, do a little sanity checking and overwrite the table + * in memory with the values from the file. + */ +static void +set_iadptbl(infile) +char *infile; +{ + int i; + int niadpents; + char *tokp; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + iaadmin_t iaadmin; + iadpent_t *ia_dptbl; + int linenum; + ulong_t res; + hrtimer_t hrtime; + FILE *fp; + char buf[512]; + int wslength; + + (void) strcpy(pcinfo.pc_clname, "IA"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get IA class ID, priocntl system " + "call failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&iaadmin; + iaadmin.ia_cmd = IA_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ia_dptbl size, priocntl system " + "call failed with errno %d\n", basenm, errno); + + niadpents = iaadmin.ia_ndpents; + if ((ia_dptbl = + (iadpent_t *)malloc(niadpents * sizeof (iadpent_t))) == NULL) + fatalerr("%s: Can't allocate memory for ia_dptbl\n", basenm); + + if ((fp = fopen(infile, "r")) == NULL) + fatalerr("%s: Can't open %s for input\n", basenm, infile); + + linenum = 0; + + /* + * Find the first non-blank, non-comment line. A comment line + * is any line with '#' as the first non-white-space character. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + if ((int)strlen(tokp) > 4) { + if (strncmp(tokp, "RES=", 4) != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[4] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[4], (char **)NULL, 10); + } else if (strlen(tokp) == 4) { + if (strcmp(tokp, "RES=") != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } else if (strlen(tokp) == 3) { + if (strcmp(tokp, "RES") != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((int)strlen(tokp) > 1) { + if (strncmp(tokp, "=", 1) != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[1] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[1], (char **)NULL, 10); + } else if (strlen(tokp) == 1) { + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } + } else { + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + } + + /* + * The remainder of the input file should contain exactly enough + * non-blank, non-comment lines to fill the table (ia_ndpents lines). + * We assume that any non-blank, non-comment line is data for the + * table and fail if we find more or less than we need. + */ + for (i = 0; i < iaadmin.ia_ndpents; i++) { + + /* + * Get the next non-blank, non-comment line. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", + basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + + if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = atol(tokp); + hrtime.hrt_res = res; + if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert specified \ +resolution to ticks\n", basenm); + if ((ia_dptbl[i].ia_quantum = hrtconvert(&hrtime)) + == -1) + fatalerr("%s: ia_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", + basenm, linenum); + } else { + ia_dptbl[i].ia_quantum = atol(tokp); + } + if (ia_dptbl[i].ia_quantum <= 0) + fatalerr("%s: ia_quantum value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ia_dptbl[i].ia_tqexp = (short)atoi(tokp); + if (ia_dptbl[i].ia_tqexp < 0 || + ia_dptbl[i].ia_tqexp > iaadmin.ia_ndpents) + fatalerr("%s: ia_tqexp value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ia_dptbl[i].ia_slpret = (short)atoi(tokp); + if (ia_dptbl[i].ia_slpret < 0 || + ia_dptbl[i].ia_slpret > iaadmin.ia_ndpents) + fatalerr("%s: ia_slpret value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ia_dptbl[i].ia_maxwait = (short)atoi(tokp); + if (ia_dptbl[i].ia_maxwait < 0) + fatalerr("%s: ia_maxwait value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ia_dptbl[i].ia_lwait = (short)atoi(tokp); + if (ia_dptbl[i].ia_lwait < 0 || + ia_dptbl[i].ia_lwait > iaadmin.ia_ndpents) + fatalerr("%s: ia_lwait value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') + fatalerr("%s: Too many values, line %d of input file\n", + basenm, linenum); + } + + /* + * We've read enough lines to fill the table. We fail + * if the input file contains any more. + */ + while (fgets(buf, sizeof (buf), fp) != NULL) { + if (buf[0] != '#' && buf[0] != '\0' && + (wslength = strspn(buf, " \t\n")) != strlen(buf) && + strchr(buf, '#') != buf + wslength) + fatalerr("%s: Too many lines in input table\n", + basenm); + } + + iaadmin.ia_dpents = ia_dptbl; + iaadmin.ia_cmd = IA_SETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't set ia_dptbl, priocntl system call \ +failed with errno %d\n", basenm, errno); +} diff --git a/usr/src/cmd/dispadmin/rtdispadmin.c b/usr/src/cmd/dispadmin/rtdispadmin.c new file mode 100644 index 0000000000..6f18bf1f39 --- /dev/null +++ b/usr/src/cmd/dispadmin/rtdispadmin.c @@ -0,0 +1,384 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/priocntl.h> +#include <sys/rtpriocntl.h> +#include <sys/param.h> +#include <sys/rt.h> + +#include "dispadmin.h" + +/* + * This file contains the class specific code implementing + * the real-time dispadmin sub-command. + */ + +#define BASENMSZ 16 + +extern char *basename(); + +static void get_rtdptbl(), set_rtdptbl(); + +static char usage[] = "usage: dispadmin -l\n" + "dispadmin -c RT -g [-r res]\n" + "dispadmin -c RT -s infile\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[256]; + + +int +main(int argc, char **argv) +{ + extern char *optarg; + + int c; + int lflag, gflag, rflag, sflag; + ulong_t res; + char *infile; + + (void) strcpy(cmdpath, argv[0]); + (void) strcpy(basenm, basename(argv[0])); + lflag = gflag = rflag = sflag = 0; + while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { + switch (c) { + + case 'l': + lflag++; + break; + + case 'c': + if (strcmp(optarg, "RT") != 0) + fatalerr("error: %s executed for %s class, " + "%s is actually sub-command for RT class\n", + cmdpath, optarg, cmdpath); + break; + + case 'g': + gflag++; + break; + + case 'r': + rflag++; + res = strtoul(optarg, (char **)NULL, 10); + break; + + case 's': + sflag++; + infile = optarg; + break; + + case '?': + fatalerr(usage); + + default: + break; + } + } + + if (lflag) { + if (gflag || rflag || sflag) + fatalerr(usage); + + (void) printf("RT\t(Real Time)\n"); + return (0); + + } else if (gflag) { + if (lflag || sflag) + fatalerr(usage); + + if (rflag == 0) + res = 1000; + + get_rtdptbl(res); + return (0); + + } else if (sflag) { + if (lflag || gflag || rflag) + fatalerr(usage); + + set_rtdptbl(infile); + return (0); + + } else { + fatalerr(usage); + } + return (1); +} + + +/* + * Retrieve the current rt_dptbl from memory, convert the time quantum + * values to the resolution specified by res and write the table to stdout. + */ +static void +get_rtdptbl(ulong_t res) +{ + int i; + int rtdpsz; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + rtadmin_t rtadmin; + rtdpent_t *rt_dptbl; + hrtimer_t hrtime; + + (void) strcpy(pcinfo.pc_clname, "RT"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get RT class ID, priocntl system call " + "failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&rtadmin; + rtadmin.rt_cmd = RT_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get rt_dptbl size, priocntl system call " + "failed with errno %d\n", basenm, errno); + + rtdpsz = rtadmin.rt_ndpents * sizeof (rtdpent_t); + if ((rt_dptbl = (rtdpent_t *)malloc(rtdpsz)) == NULL) + fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm); + + rtadmin.rt_dpents = rt_dptbl; + + rtadmin.rt_cmd = RT_GETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get rt_dptbl, priocntl system call " + "failed with errno %d\n", basenm, errno); + + (void) printf("# Real Time Dispatcher Configuration\n"); + (void) printf("RES=%ld\n\n", res); + (void) printf("# TIME QUANTUM PRIORITY\n"); + (void) printf("# (rt_quantum) LEVEL\n"); + + for (i = 0; i < rtadmin.rt_ndpents; i++) { + if (res != HZ && rt_dptbl[i].rt_quantum != RT_TQINF) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = rt_dptbl[i].rt_quantum; + hrtime.hrt_res = HZ; + if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert to requested " + "resolution\n", basenm); + if ((rt_dptbl[i].rt_quantum = + hrtconvert(&hrtime)) == -1) + fatalerr("%s: Can't express time quantum in " + "requested resolution,\n" + "try coarser resolution\n", basenm); + } + (void) printf("%10d # %3d\n", + rt_dptbl[i].rt_quantum, i); + } +} + + +/* + * Read the rt_dptbl values from infile, convert the time quantum values + * to HZ resolution, do a little sanity checking and overwrite the table + * in memory with the values from the file. + */ +static void +set_rtdptbl(infile) +char *infile; +{ + int i; + int nrtdpents; + char *tokp; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + rtadmin_t rtadmin; + rtdpent_t *rt_dptbl; + int linenum; + ulong_t res; + hrtimer_t hrtime; + FILE *fp; + char buf[512]; + int wslength; + + (void) strcpy(pcinfo.pc_clname, "RT"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get RT class ID, priocntl system call " + "failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&rtadmin; + rtadmin.rt_cmd = RT_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get rt_dptbl size, priocntl system call " + "failed with errno %d\n", basenm, errno); + + nrtdpents = rtadmin.rt_ndpents; + if ((rt_dptbl = + (rtdpent_t *)malloc(nrtdpents * sizeof (rtdpent_t))) == NULL) + fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm); + + if ((fp = fopen(infile, "r")) == NULL) + fatalerr("%s: Can't open %s for input\n", basenm, infile); + + linenum = 0; + + /* + * Find the first non-blank, non-comment line. A comment line + * is any line with '#' as the first non-white-space character. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + if ((int)strlen(tokp) > 4) { + if (strncmp(tokp, "RES=", 4) != 0) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if (tokp[4] == '-') + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[4], (char **)NULL, 10); + } else if (strlen(tokp) == 4) { + if (strcmp(tokp, "RES=") != 0) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } else if (strlen(tokp) == 3) { + if (strcmp(tokp, "RES") != 0) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if ((int)strlen(tokp) > 1) { + if (strncmp(tokp, "=", 1) != 0) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if (tokp[1] == '-') + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[1], (char **)NULL, 10); + } else if (strlen(tokp) == 1) { + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, " + "line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } + } else { + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + } + + /* + * The remainder of the input file should contain exactly enough + * non-blank, non-comment lines to fill the table (rt_ndpents lines). + * We assume that any non-blank, non-comment line is data for the + * table and fail if we find more or less than we need. + */ + for (i = 0; i < rtadmin.rt_ndpents; i++) { + + /* + * Get the next non-blank, non-comment line. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", + basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + + rt_dptbl[i].rt_quantum = atol(tokp); + if (rt_dptbl[i].rt_quantum <= 0) { + if (rt_dptbl[i].rt_quantum != RT_TQINF) + fatalerr("%s: rt_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", basenm, linenum); + } else if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = rt_dptbl[i].rt_quantum; + hrtime.hrt_res = res; + if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert specified " + "resolution to ticks\n", basenm); + if ((rt_dptbl[i].rt_quantum = + hrtconvert(&hrtime)) == -1) + fatalerr("%s: rt_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", basenm, linenum); + } + + if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') + fatalerr("%s: Too many values, line %d of input file\n", + basenm, linenum); + } + + /* + * We've read enough lines to fill the table. We fail + * if the input file contains any more. + */ + while (fgets(buf, sizeof (buf), fp) != NULL) { + if (buf[0] != '#' && buf[0] != '\0' && + (wslength = strspn(buf, " \t\n")) != strlen(buf) && + strchr(buf, '#') != buf + wslength) + fatalerr("%s: Too many lines in input table\n", + basenm); + } + + rtadmin.rt_dpents = rt_dptbl; + rtadmin.rt_cmd = RT_SETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't set rt_dptbl, priocntl system call failed " + "with errno %d\n", basenm, errno); +} diff --git a/usr/src/cmd/dispadmin/subr.c b/usr/src/cmd/dispadmin/subr.c new file mode 100644 index 0000000000..b2c5c10b4a --- /dev/null +++ b/usr/src/cmd/dispadmin/subr.c @@ -0,0 +1,255 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <limits.h> + +#include "dispadmin.h" + + +/* + * Utility functions for dispadmin command. + */ + + +void +fatalerr(const char *format, ...) +{ + va_list ap; + + (void) va_start(ap, format); + (void) vfprintf(stderr, format, ap); + va_end(ap); + exit(1); +} + + +/* + * hrtconvert() returns the interval specified by htp as a single + * value in resolution htp->hrt_res. Returns -1 on overflow. + */ +long +hrtconvert(hrtimer_t *htp) +{ + long sum; + long product; + + product = htp->hrt_secs * htp->hrt_res; + + if (product / htp->hrt_res == htp->hrt_secs) { + sum = product + htp->hrt_rem; + if (sum - htp->hrt_rem == product) { + return (sum); + } + } + return (-1); +} + +/* + * The following routine was removed from libc (libc/port/gen/hrtnewres.c). + * It has also been added to priocntl, so if you fix it here, you should + * also probably fix it there. In the long term, this should be recoded to + * not be hrt'ish. + */ + +/* + * Convert interval expressed in htp->hrt_res to new_res. + * + * Calculate: (interval * new_res) / htp->hrt_res rounding off as + * specified by round. + * + * Note: All args are assumed to be positive. If + * the last divide results in something bigger than + * a long, then -1 is returned instead. + */ + +int +_hrtnewres(hrtimer_t *htp, ulong_t new_res, long round) +{ + long interval; + longlong_t dint; + longlong_t dto_res; + longlong_t drem; + longlong_t dfrom_res; + longlong_t prod; + longlong_t quot; + long numerator; + long result; + ulong_t modulus; + ulong_t twomodulus; + long temp; + + if (htp->hrt_res == 0 || new_res == 0 || + new_res > NANOSEC || htp->hrt_rem < 0) + return (-1); + + if (htp->hrt_rem >= htp->hrt_res) { + htp->hrt_secs += htp->hrt_rem / htp->hrt_res; + htp->hrt_rem = htp->hrt_rem % htp->hrt_res; + } + + interval = htp->hrt_rem; + if (interval == 0) { + htp->hrt_res = new_res; + return (0); + } + + /* + * Try to do the calculations in single precision first + * (for speed). If they overflow, use double precision. + * What we want to compute is: + * + * (interval * new_res) / hrt->hrt_res + */ + + numerator = interval * new_res; + + if (numerator / new_res == interval) { + + /* + * The above multiply didn't give overflow since + * the division got back the original number. Go + * ahead and compute the result. + */ + + result = numerator / htp->hrt_res; + + /* + * For HRT_RND, compute the value of: + * + * (interval * new_res) % htp->hrt_res + * + * If it is greater than half of the htp->hrt_res, + * then rounding increases the result by 1. + * + * For HRT_RNDUP, we increase the result by 1 if: + * + * result * htp->hrt_res != numerator + * + * because this tells us we truncated when calculating + * result above. + * + * We also check for overflow when incrementing result + * although this is extremely rare. + */ + + if (round == HRT_RND) { + modulus = numerator - result * htp->hrt_res; + if ((twomodulus = 2 * modulus) / 2 == modulus) { + + /* + * No overflow (if we overflow in calculation + * of twomodulus we fall through and use + * double precision). + */ + if (twomodulus >= htp->hrt_res) { + temp = result + 1; + if (temp - 1 == result) + result++; + else + return (-1); + } + htp->hrt_res = new_res; + htp->hrt_rem = result; + return (0); + } + } else if (round == HRT_RNDUP) { + if (result * htp->hrt_res != numerator) { + temp = result + 1; + if (temp - 1 == result) + result++; + else + return (-1); + } + htp->hrt_res = new_res; + htp->hrt_rem = result; + return (0); + } else { /* round == HRT_TRUNC */ + htp->hrt_res = new_res; + htp->hrt_rem = result; + return (0); + } + } + + /* + * We would get overflow doing the calculation is + * single precision so do it the slow but careful way. + * + * Compute the interval times the resolution we are + * going to. + */ + + dint = interval; + dto_res = new_res; + prod = dint * dto_res; + + /* + * For HRT_RND the result will be equal to: + * + * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res + * + * and for HRT_RNDUP we use: + * + * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res + * + * This is a different but equivalent way of rounding. + */ + + if (round == HRT_RND) { + drem = htp->hrt_res / 2; + prod = prod + drem; + } else if (round == HRT_RNDUP) { + drem = htp->hrt_res - 1; + prod = prod + drem; + } + + dfrom_res = htp->hrt_res; + quot = prod / dfrom_res; + + /* + * If the quotient won't fit in a long, then we have + * overflow. Otherwise, return the result. + */ + + if (quot > UINT_MAX) { + return (-1); + } else { + htp->hrt_res = new_res; + htp->hrt_rem = (int)quot; + return (0); + } +} diff --git a/usr/src/cmd/dispadmin/tsdispadmin.c b/usr/src/cmd/dispadmin/tsdispadmin.c new file mode 100644 index 0000000000..83bb6dd2c3 --- /dev/null +++ b/usr/src/cmd/dispadmin/tsdispadmin.c @@ -0,0 +1,426 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/priocntl.h> +#include <sys/tspriocntl.h> +#include <sys/param.h> +#include <sys/ts.h> + +#include "dispadmin.h" + +/* + * This file contains the class specific code implementing + * the time-sharing dispadmin sub-command. + */ + +#define BASENMSZ 16 + +extern char *basename(); + +static void get_tsdptbl(), set_tsdptbl(); + +static char usage[] = +"usage: dispadmin -l\n\ + dispadmin -c TS -g [-r res]\n\ + dispadmin -c TS -s infile\n"; + +static char basenm[BASENMSZ]; +static char cmdpath[256]; + + +int +main(int argc, char **argv) +{ + extern char *optarg; + + int c; + int lflag, gflag, rflag, sflag; + ulong_t res; + char *infile; + + (void) strcpy(cmdpath, argv[0]); + (void) strcpy(basenm, basename(argv[0])); + lflag = gflag = rflag = sflag = 0; + while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { + switch (c) { + + case 'l': + lflag++; + break; + + case 'c': + if (strcmp(optarg, "TS") != 0) + fatalerr("error: %s executed for %s class, \ +%s is actually sub-command for TS class\n", cmdpath, optarg, cmdpath); + break; + + case 'g': + gflag++; + break; + + case 'r': + rflag++; + res = strtoul(optarg, (char **)NULL, 10); + break; + + case 's': + sflag++; + infile = optarg; + break; + + case '?': + fatalerr(usage); + + default: + break; + } + } + + if (lflag) { + if (gflag || rflag || sflag) + fatalerr(usage); + + (void) printf("TS\t(Time Sharing)\n"); + return (0); + + } else if (gflag) { + if (lflag || sflag) + fatalerr(usage); + + if (rflag == 0) + res = 1000; + + get_tsdptbl(res); + return (0); + + } else if (sflag) { + if (lflag || gflag || rflag) + fatalerr(usage); + + set_tsdptbl(infile); + return (0); + + } else { + fatalerr(usage); + } + return (1); +} + + +/* + * Retrieve the current ts_dptbl from memory, convert the time quantum + * values to the resolution specified by res and write the table to stdout. + */ +static void +get_tsdptbl(ulong_t res) +{ + int i; + int tsdpsz; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + tsadmin_t tsadmin; + tsdpent_t *ts_dptbl; + hrtimer_t hrtime; + + (void) strcpy(pcinfo.pc_clname, "TS"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get TS class ID, priocntl system \ +call failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&tsadmin; + tsadmin.ts_cmd = TS_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ts_dptbl size, priocntl system \ +call failed with errno %d\n", basenm, errno); + + tsdpsz = tsadmin.ts_ndpents * sizeof (tsdpent_t); + if ((ts_dptbl = (tsdpent_t *)malloc(tsdpsz)) == NULL) + fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm); + + tsadmin.ts_dpents = ts_dptbl; + + tsadmin.ts_cmd = TS_GETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ts_dptbl, priocntl system call \ +call failed with errno %d\n", basenm, errno); + + (void) printf("# Time Sharing Dispatcher Configuration\n"); + (void) printf("RES=%ld\n\n", res); + (void) printf("# ts_quantum ts_tqexp ts_slpret ts_maxwait ts_lwait \ +PRIORITY LEVEL\n"); + + for (i = 0; i < tsadmin.ts_ndpents; i++) { + if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = ts_dptbl[i].ts_quantum; + hrtime.hrt_res = HZ; + if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert to requested \ +resolution\n", basenm); + if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime)) + == -1) + fatalerr("%s: Can't express time quantum in " + "requested resolution,\n" + "try coarser resolution\n", basenm); + } + (void) printf("%10d%10d%10d%12d%10d # %3d\n", + ts_dptbl[i].ts_quantum, ts_dptbl[i].ts_tqexp, + ts_dptbl[i].ts_slpret, ts_dptbl[i].ts_maxwait, + ts_dptbl[i].ts_lwait, i); + } +} + + +/* + * Read the ts_dptbl values from infile, convert the time quantum values + * to HZ resolution, do a little sanity checking and overwrite the table + * in memory with the values from the file. + */ +static void +set_tsdptbl(infile) +char *infile; +{ + int i; + int ntsdpents; + char *tokp; + pcinfo_t pcinfo; + pcadmin_t pcadmin; + tsadmin_t tsadmin; + tsdpent_t *ts_dptbl; + int linenum; + ulong_t res; + hrtimer_t hrtime; + FILE *fp; + char buf[512]; + int wslength; + + (void) strcpy(pcinfo.pc_clname, "TS"); + if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) + fatalerr("%s: Can't get TS class ID, priocntl system \ +call failed with errno %d\n", basenm, errno); + + pcadmin.pc_cid = pcinfo.pc_cid; + pcadmin.pc_cladmin = (char *)&tsadmin; + tsadmin.ts_cmd = TS_GETDPSIZE; + + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't get ts_dptbl size, priocntl system \ +call failed with errno %d\n", basenm, errno); + + ntsdpents = tsadmin.ts_ndpents; + if ((ts_dptbl = + (tsdpent_t *)malloc(ntsdpents * sizeof (tsdpent_t))) == NULL) + fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm); + + if ((fp = fopen(infile, "r")) == NULL) + fatalerr("%s: Can't open %s for input\n", basenm, infile); + + linenum = 0; + + /* + * Find the first non-blank, non-comment line. A comment line + * is any line with '#' as the first non-white-space character. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + if ((int)strlen(tokp) > 4) { + if (strncmp(tokp, "RES=", 4) != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[4] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[4], (char **)NULL, 10); + } else if (strlen(tokp) == 4) { + if (strcmp(tokp, "RES=") != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } else if (strlen(tokp) == 3) { + if (strcmp(tokp, "RES") != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if ((int)strlen(tokp) > 1) { + if (strncmp(tokp, "=", 1) != 0) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[1] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(&tokp[1], (char **)NULL, 10); + } else if (strlen(tokp) == 1) { + if ((tokp = strtok(NULL, " \t")) == NULL) + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + if (tokp[0] == '-') + fatalerr("%s: Bad RES specification, \ +line %d of input file\n", basenm, linenum); + res = strtoul(tokp, (char **)NULL, 10); + } + } else { + fatalerr("%s: Bad RES specification, line %d of input file\n", + basenm, linenum); + } + + /* + * The remainder of the input file should contain exactly enough + * non-blank, non-comment lines to fill the table (ts_ndpents lines). + * We assume that any non-blank, non-comment line is data for the + * table and fail if we find more or less than we need. + */ + for (i = 0; i < tsadmin.ts_ndpents; i++) { + + /* + * Get the next non-blank, non-comment line. + */ + do { + if (fgets(buf, sizeof (buf), fp) == NULL) + fatalerr("%s: Too few lines in input table\n", + basenm); + linenum++; + } while (buf[0] == '#' || buf[0] == '\0' || + (wslength = strspn(buf, " \t\n")) == strlen(buf) || + strchr(buf, '#') == buf + wslength); + + if ((tokp = strtok(buf, " \t")) == NULL) + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + + if (res != HZ) { + hrtime.hrt_secs = 0; + hrtime.hrt_rem = atol(tokp); + hrtime.hrt_res = res; + if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) + fatalerr("%s: Can't convert specified " + "resolution to ticks\n", basenm); + if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime)) + == -1) + fatalerr("%s: ts_quantum value out of " + "valid range; line %d of input,\n" + "table not overwritten\n", + basenm, linenum); + } else { + ts_dptbl[i].ts_quantum = atol(tokp); + } + if (ts_dptbl[i].ts_quantum <= 0) + fatalerr("%s: ts_quantum value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ts_dptbl[i].ts_tqexp = (short)atoi(tokp); + if (ts_dptbl[i].ts_tqexp < 0 || + ts_dptbl[i].ts_tqexp > tsadmin.ts_ndpents) + fatalerr("%s: ts_tqexp value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ts_dptbl[i].ts_slpret = (short)atoi(tokp); + if (ts_dptbl[i].ts_slpret < 0 || + ts_dptbl[i].ts_slpret > tsadmin.ts_ndpents) + fatalerr("%s: ts_slpret value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ts_dptbl[i].ts_maxwait = (short)atoi(tokp); + if (ts_dptbl[i].ts_maxwait < 0) + fatalerr("%s: ts_maxwait value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#') + fatalerr("%s: Too few values, line %d of input file\n", + basenm, linenum); + ts_dptbl[i].ts_lwait = (short)atoi(tokp); + if (ts_dptbl[i].ts_lwait < 0 || + ts_dptbl[i].ts_lwait > tsadmin.ts_ndpents) + fatalerr("%s: ts_lwait value out of valid range; " + "line %d of input,\ntable not overwritten\n", + basenm, linenum); + + if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') + fatalerr("%s: Too many values, line %d of input file\n", + basenm, linenum); + } + + /* + * We've read enough lines to fill the table. We fail + * if the input file contains any more. + */ + while (fgets(buf, sizeof (buf), fp) != NULL) { + if (buf[0] != '#' && buf[0] != '\0' && + (wslength = strspn(buf, " \t\n")) != strlen(buf) && + strchr(buf, '#') != buf + wslength) + fatalerr("%s: Too many lines in input table\n", + basenm); + } + + tsadmin.ts_dpents = ts_dptbl; + tsadmin.ts_cmd = TS_SETDPTBL; + if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) + fatalerr("%s: Can't set ts_dptbl, priocntl system call \ +failed with errno %d\n", basenm, errno); +} |
