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