1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <errno.h> 38 #include <sys/types.h> 39 #include <sys/priocntl.h> 40 #include <sys/rtpriocntl.h> 41 #include <sys/param.h> 42 #include <sys/rt.h> 43 44 #include "dispadmin.h" 45 46 /* 47 * This file contains the class specific code implementing 48 * the real-time dispadmin sub-command. 49 */ 50 51 #define BASENMSZ 16 52 53 extern char *basename(); 54 55 static void get_rtdptbl(), set_rtdptbl(); 56 57 static char usage[] = "usage: dispadmin -l\n" 58 "dispadmin -c RT -g [-r res]\n" 59 "dispadmin -c RT -s infile\n"; 60 61 static char basenm[BASENMSZ]; 62 static char cmdpath[256]; 63 64 65 int 66 main(int argc, char **argv) 67 { 68 extern char *optarg; 69 70 int c; 71 int lflag, gflag, rflag, sflag; 72 ulong_t res; 73 char *infile; 74 75 (void) strcpy(cmdpath, argv[0]); 76 (void) strcpy(basenm, basename(argv[0])); 77 lflag = gflag = rflag = sflag = 0; 78 while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) { 79 switch (c) { 80 81 case 'l': 82 lflag++; 83 break; 84 85 case 'c': 86 if (strcmp(optarg, "RT") != 0) 87 fatalerr("error: %s executed for %s class, " 88 "%s is actually sub-command for RT class\n", 89 cmdpath, optarg, cmdpath); 90 break; 91 92 case 'g': 93 gflag++; 94 break; 95 96 case 'r': 97 rflag++; 98 res = strtoul(optarg, (char **)NULL, 10); 99 break; 100 101 case 's': 102 sflag++; 103 infile = optarg; 104 break; 105 106 case '?': 107 fatalerr(usage); 108 109 default: 110 break; 111 } 112 } 113 114 if (lflag) { 115 if (gflag || rflag || sflag) 116 fatalerr(usage); 117 118 (void) printf("RT\t(Real Time)\n"); 119 return (0); 120 121 } else if (gflag) { 122 if (lflag || sflag) 123 fatalerr(usage); 124 125 if (rflag == 0) 126 res = 1000; 127 128 get_rtdptbl(res); 129 return (0); 130 131 } else if (sflag) { 132 if (lflag || gflag || rflag) 133 fatalerr(usage); 134 135 set_rtdptbl(infile); 136 return (0); 137 138 } else { 139 fatalerr(usage); 140 } 141 return (1); 142 } 143 144 145 /* 146 * Retrieve the current rt_dptbl from memory, convert the time quantum 147 * values to the resolution specified by res and write the table to stdout. 148 */ 149 static void 150 get_rtdptbl(ulong_t res) 151 { 152 int i; 153 int rtdpsz; 154 pcinfo_t pcinfo; 155 pcadmin_t pcadmin; 156 rtadmin_t rtadmin; 157 rtdpent_t *rt_dptbl; 158 hrtimer_t hrtime; 159 160 (void) strcpy(pcinfo.pc_clname, "RT"); 161 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 162 fatalerr("%s: Can't get RT class ID, priocntl system call " 163 "failed with errno %d\n", basenm, errno); 164 165 pcadmin.pc_cid = pcinfo.pc_cid; 166 pcadmin.pc_cladmin = (char *)&rtadmin; 167 rtadmin.rt_cmd = RT_GETDPSIZE; 168 169 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) 170 fatalerr("%s: Can't get rt_dptbl size, priocntl system call " 171 "failed with errno %d\n", basenm, errno); 172 173 rtdpsz = rtadmin.rt_ndpents * sizeof (rtdpent_t); 174 if ((rt_dptbl = (rtdpent_t *)malloc(rtdpsz)) == NULL) 175 fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm); 176 177 rtadmin.rt_dpents = rt_dptbl; 178 179 rtadmin.rt_cmd = RT_GETDPTBL; 180 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) 181 fatalerr("%s: Can't get rt_dptbl, priocntl system call " 182 "failed with errno %d\n", basenm, errno); 183 184 (void) printf("# Real Time Dispatcher Configuration\n"); 185 (void) printf("RES=%ld\n\n", res); 186 (void) printf("# TIME QUANTUM PRIORITY\n"); 187 (void) printf("# (rt_quantum) LEVEL\n"); 188 189 for (i = 0; i < rtadmin.rt_ndpents; i++) { 190 if (res != HZ && rt_dptbl[i].rt_quantum != RT_TQINF) { 191 hrtime.hrt_secs = 0; 192 hrtime.hrt_rem = rt_dptbl[i].rt_quantum; 193 hrtime.hrt_res = HZ; 194 if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) 195 fatalerr("%s: Can't convert to requested " 196 "resolution\n", basenm); 197 if ((rt_dptbl[i].rt_quantum = 198 hrtconvert(&hrtime)) == -1) 199 fatalerr("%s: Can't express time quantum in " 200 "requested resolution,\n" 201 "try coarser resolution\n", basenm); 202 } 203 (void) printf("%10d # %3d\n", 204 rt_dptbl[i].rt_quantum, i); 205 } 206 } 207 208 209 /* 210 * Read the rt_dptbl values from infile, convert the time quantum values 211 * to HZ resolution, do a little sanity checking and overwrite the table 212 * in memory with the values from the file. 213 */ 214 static void 215 set_rtdptbl(infile) 216 char *infile; 217 { 218 int i; 219 int nrtdpents; 220 char *tokp; 221 pcinfo_t pcinfo; 222 pcadmin_t pcadmin; 223 rtadmin_t rtadmin; 224 rtdpent_t *rt_dptbl; 225 int linenum; 226 ulong_t res; 227 hrtimer_t hrtime; 228 FILE *fp; 229 char buf[512]; 230 int wslength; 231 232 (void) strcpy(pcinfo.pc_clname, "RT"); 233 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 234 fatalerr("%s: Can't get RT class ID, priocntl system call " 235 "failed with errno %d\n", basenm, errno); 236 237 pcadmin.pc_cid = pcinfo.pc_cid; 238 pcadmin.pc_cladmin = (char *)&rtadmin; 239 rtadmin.rt_cmd = RT_GETDPSIZE; 240 241 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) 242 fatalerr("%s: Can't get rt_dptbl size, priocntl system call " 243 "failed with errno %d\n", basenm, errno); 244 245 nrtdpents = rtadmin.rt_ndpents; 246 if ((rt_dptbl = 247 (rtdpent_t *)malloc(nrtdpents * sizeof (rtdpent_t))) == NULL) 248 fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm); 249 250 if ((fp = fopen(infile, "r")) == NULL) 251 fatalerr("%s: Can't open %s for input\n", basenm, infile); 252 253 linenum = 0; 254 255 /* 256 * Find the first non-blank, non-comment line. A comment line 257 * is any line with '#' as the first non-white-space character. 258 */ 259 do { 260 if (fgets(buf, sizeof (buf), fp) == NULL) 261 fatalerr("%s: Too few lines in input table\n", basenm); 262 linenum++; 263 } while (buf[0] == '#' || buf[0] == '\0' || 264 (wslength = strspn(buf, " \t\n")) == strlen(buf) || 265 strchr(buf, '#') == buf + wslength); 266 267 if ((tokp = strtok(buf, " \t")) == NULL) 268 fatalerr("%s: Bad RES specification, line %d of input file\n", 269 basenm, linenum); 270 if ((int)strlen(tokp) > 4) { 271 if (strncmp(tokp, "RES=", 4) != 0) 272 fatalerr("%s: Bad RES specification, " 273 "line %d of input file\n", basenm, linenum); 274 if (tokp[4] == '-') 275 fatalerr("%s: Bad RES specification, " 276 "line %d of input file\n", basenm, linenum); 277 res = strtoul(&tokp[4], (char **)NULL, 10); 278 } else if (strlen(tokp) == 4) { 279 if (strcmp(tokp, "RES=") != 0) 280 fatalerr("%s: Bad RES specification, " 281 "line %d of input file\n", basenm, linenum); 282 if ((tokp = strtok(NULL, " \t")) == NULL) 283 fatalerr("%s: Bad RES specification, " 284 "line %d of input file\n", basenm, linenum); 285 if (tokp[0] == '-') 286 fatalerr("%s: Bad RES specification, " 287 "line %d of input file\n", basenm, linenum); 288 res = strtoul(tokp, (char **)NULL, 10); 289 } else if (strlen(tokp) == 3) { 290 if (strcmp(tokp, "RES") != 0) 291 fatalerr("%s: Bad RES specification, " 292 "line %d of input file\n", basenm, linenum); 293 if ((tokp = strtok(NULL, " \t")) == NULL) 294 fatalerr("%s: Bad RES specification, " 295 "line %d of input file\n", basenm, linenum); 296 if ((int)strlen(tokp) > 1) { 297 if (strncmp(tokp, "=", 1) != 0) 298 fatalerr("%s: Bad RES specification, " 299 "line %d of input file\n", basenm, linenum); 300 if (tokp[1] == '-') 301 fatalerr("%s: Bad RES specification, " 302 "line %d of input file\n", basenm, linenum); 303 res = strtoul(&tokp[1], (char **)NULL, 10); 304 } else if (strlen(tokp) == 1) { 305 if ((tokp = strtok(NULL, " \t")) == NULL) 306 fatalerr("%s: Bad RES specification, " 307 "line %d of input file\n", basenm, linenum); 308 if (tokp[0] == '-') 309 fatalerr("%s: Bad RES specification, " 310 "line %d of input file\n", basenm, linenum); 311 res = strtoul(tokp, (char **)NULL, 10); 312 } 313 } else { 314 fatalerr("%s: Bad RES specification, line %d of input file\n", 315 basenm, linenum); 316 } 317 318 /* 319 * The remainder of the input file should contain exactly enough 320 * non-blank, non-comment lines to fill the table (rt_ndpents lines). 321 * We assume that any non-blank, non-comment line is data for the 322 * table and fail if we find more or less than we need. 323 */ 324 for (i = 0; i < rtadmin.rt_ndpents; i++) { 325 326 /* 327 * Get the next non-blank, non-comment line. 328 */ 329 do { 330 if (fgets(buf, sizeof (buf), fp) == NULL) 331 fatalerr("%s: Too few lines in input table\n", 332 basenm); 333 linenum++; 334 } while (buf[0] == '#' || buf[0] == '\0' || 335 (wslength = strspn(buf, " \t\n")) == strlen(buf) || 336 strchr(buf, '#') == buf + wslength); 337 338 if ((tokp = strtok(buf, " \t")) == NULL) 339 fatalerr("%s: Too few values, line %d of input file\n", 340 basenm, linenum); 341 342 rt_dptbl[i].rt_quantum = atol(tokp); 343 if (rt_dptbl[i].rt_quantum <= 0) { 344 if (rt_dptbl[i].rt_quantum != RT_TQINF) 345 fatalerr("%s: rt_quantum value out of " 346 "valid range; line %d of input,\n" 347 "table not overwritten\n", basenm, linenum); 348 } else if (res != HZ) { 349 hrtime.hrt_secs = 0; 350 hrtime.hrt_rem = rt_dptbl[i].rt_quantum; 351 hrtime.hrt_res = res; 352 if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) 353 fatalerr("%s: Can't convert specified " 354 "resolution to ticks\n", basenm); 355 if ((rt_dptbl[i].rt_quantum = 356 hrtconvert(&hrtime)) == -1) 357 fatalerr("%s: rt_quantum value out of " 358 "valid range; line %d of input,\n" 359 "table not overwritten\n", basenm, linenum); 360 } 361 362 if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') 363 fatalerr("%s: Too many values, line %d of input file\n", 364 basenm, linenum); 365 } 366 367 /* 368 * We've read enough lines to fill the table. We fail 369 * if the input file contains any more. 370 */ 371 while (fgets(buf, sizeof (buf), fp) != NULL) { 372 if (buf[0] != '#' && buf[0] != '\0' && 373 (wslength = strspn(buf, " \t\n")) != strlen(buf) && 374 strchr(buf, '#') != buf + wslength) 375 fatalerr("%s: Too many lines in input table\n", 376 basenm); 377 } 378 379 rtadmin.rt_dpents = rt_dptbl; 380 rtadmin.rt_cmd = RT_SETDPTBL; 381 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) 382 fatalerr("%s: Can't set rt_dptbl, priocntl system call failed " 383 "with errno %d\n", basenm, errno); 384 } 385