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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The plgrp utility allows a user to display and modify the home lgroup and 31 * lgroup affinities of the specified threads 32 */ 33 34 #include <ctype.h> 35 #include <errno.h> 36 #include <libintl.h> 37 #include <libproc.h> 38 #include <locale.h> 39 #include <signal.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <strings.h> 43 #include <unistd.h> 44 #include <libgen.h> 45 #include <sys/lgrp_user.h> 46 47 48 /* 49 * Delimiters 50 */ 51 #define DELIMIT_AFF '/' /* lgroup affinity from lgroups */ 52 #define DELIMIT_LGRP "," /* lgroups from each other */ 53 #define DELIMIT_LWP "/" /* thread/LWP IDs from process ID */ 54 #define DELIMIT_RANGE '-' /* range of IDs (eg. lgroup) */ 55 #define DELIMIT_AFF_LST ',' /* list of affinities from another list */ 56 57 /* 58 * Exit values other than EXIT_{SUCCESS,FAILURE} 59 */ 60 #define EXIT_NONFATAL 2 /* non-fatal errors */ 61 62 /* 63 * Header and format strings 64 */ 65 #define HDR_PLGRP_AFF_GET " PID/LWPID HOME AFFINITY\n" 66 #define HDR_PLGRP_AFF_SET " PID/LWPID HOME AFFINITY\n" 67 #define HDR_PLGRP_HOME_GET " PID/LWPID HOME\n" 68 #define HDR_PLGRP_HOME_SET " PID/LWPID HOME\n" 69 70 /* 71 * Part of the HDR_PLGRP_AFF_SET header used to calculate space needed to 72 * represent changing home as old => new 73 */ 74 #define HDR_PLGRP_HOME_CHANGE "HOME " 75 76 #define FMT_AFF "%d/%s" 77 #define FMT_AFF_STR "%s" 78 #define FMT_HOME "%-6d" 79 #define FMT_NEWHOME "%d => %d" 80 #define FMT_THREAD "%8d/%-8d" 81 82 /* 83 * How much to allocate for lgroup bitmap array as it grows 84 */ 85 #define LGRP_BITMAP_CHUNK 8 86 87 /* 88 * Strings that can be given for lgroups 89 */ 90 #define LGRP_ALL_STR "all" 91 #define LGRP_LEAVES_STR "leaves" 92 #define LGRP_ROOT_STR "root" 93 94 /* 95 * Strings corresponding to lgroup affinities 96 */ 97 #define LGRP_AFF_NONE_STR "none" 98 #define LGRP_AFF_STRONG_STR "strong" 99 #define LGRP_AFF_WEAK_STR "weak" 100 101 /* 102 * Invalid value for lgroup affinity 103 */ 104 #define LGRP_AFF_INVALID -1 105 106 /* 107 * Number of args needed for lgroup system call 108 */ 109 #define LGRPSYS_NARGS 3 110 111 #ifndef TEXT_DOMAIN /* should be defined by cc -D */ 112 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */ 113 #endif 114 115 /* 116 * plgrp(1) operations 117 */ 118 typedef enum plgrp_ops { 119 PLGRP_AFFINITY_GET, 120 PLGRP_AFFINITY_SET, 121 PLGRP_HOME_GET, 122 PLGRP_HOME_SET, 123 PLGRP_NO_OP 124 } plgrp_ops_t; 125 126 /* 127 * Arguments specified to plgrp(1) and any state needed to do everything 128 * that plgrp(1) does for one operation from inside Plwp_iter_all() 129 */ 130 typedef struct plgrp_args { 131 struct ps_prochandle *Ph; /* proc handle for process */ 132 const char *lwps; /* LWPs */ 133 lgrp_id_t *lgrps; /* lgroups */ 134 lgrp_affinity_t *affs; /* lgroup affinities */ 135 int nlgrps; /* number of lgroups */ 136 int nelements; /* number of elements */ 137 int index; /* index */ 138 int nthreads; /* threads processed */ 139 plgrp_ops_t op; /* operation */ 140 } plgrp_args_t; 141 142 /* 143 * How many signals caught from terminal 144 * We bail out as soon as possible when interrupt is set 145 */ 146 static int interrupt = 0; 147 148 /* 149 * How many non-fatal errors ocurred 150 */ 151 static int nerrors = 0; 152 153 /* 154 * Name of this program 155 */ 156 static char *progname; 157 158 /* 159 * Root of the lgroup hierarchy 160 */ 161 static lgrp_id_t root = LGRP_NONE; 162 163 /* 164 * Bitmap of all lgroups in the system 165 */ 166 static char *lgrps_bitmap = NULL; 167 168 /* 169 * Size of lgrps_bitmap array 170 */ 171 static int lgrps_bitmap_nelements = 0; 172 173 /* 174 * Macro LGRP_VALID returns true when lgrp is present in the system. 175 */ 176 #define LGRP_VALID(lgrp) (lgrps_bitmap[lgrp] != 0) 177 178 179 /* 180 * Maximum lgroup value. 181 */ 182 static int max_lgrpid = LGRP_NONE; 183 184 /* 185 * Total possible number of lgroups 186 */ 187 #define NLGRPS (max_lgrpid + 1) 188 189 190 static void 191 usage(int rc) 192 { 193 (void) fprintf(stderr, 194 gettext("Usage:\t%s [-h] <pid> | <core> [/lwps] ...\n"), progname); 195 (void) fprintf(stderr, 196 gettext("\t%s [-F] -a <lgroup list> <pid>[/lwps] ...\n"), progname); 197 (void) fprintf(stderr, 198 gettext("\t%s [-F] -A <lgroup list>/none|weak|strong[,...] " 199 " <pid>[/lwps] ...\n"), progname); 200 (void) fprintf(stderr, 201 gettext("\t%s [-F] -H <lgroup list> <pid>[/lwps] ...\n"), progname); 202 (void) fprintf(stderr, 203 gettext("\n\twhere <lgroup list> is a comma separated list of\n" 204 "\tone or more of the following:\n\n" 205 "\t - lgroup ID\n" 206 "\t - Range of lgroup IDs specified as\n" 207 "\t\t<start lgroup ID>-<end lgroup ID>\n" 208 "\t - \"all\"\n" 209 "\t - \"root\"\n" 210 "\t - \"leaves\"\n\n")); 211 212 exit(rc); 213 } 214 215 /* 216 * Handler for catching signals from terminal 217 */ 218 /* ARGSUSED */ 219 static void 220 intr(int sig) 221 { 222 interrupt++; 223 } 224 225 226 /* 227 * Return string name for given lgroup affinity 228 */ 229 static char * 230 lgrp_affinity_string(lgrp_affinity_t aff) 231 { 232 char *rc = "unknown"; 233 234 switch (aff) { 235 case LGRP_AFF_STRONG: 236 rc = "strong"; 237 break; 238 case LGRP_AFF_WEAK: 239 rc = "weak"; 240 break; 241 case LGRP_AFF_NONE: 242 rc = "none"; 243 break; 244 default: 245 break; 246 } 247 248 return (rc); 249 } 250 251 252 /* 253 * Add a new lgroup into lgroup array in "arg", growing lgroup and affinity 254 * arrays if necessary 255 */ 256 static void 257 lgrps_add_lgrp(plgrp_args_t *arg, int id) 258 { 259 260 if (arg->nlgrps == arg->nelements) { 261 arg->nelements += LGRP_BITMAP_CHUNK; 262 263 arg->lgrps = realloc(arg->lgrps, 264 arg->nelements * sizeof (lgrp_id_t)); 265 if (arg->lgrps == NULL) { 266 (void) fprintf(stderr, gettext("%s: out of memory\n"), 267 progname); 268 exit(EXIT_FAILURE); 269 } 270 271 arg->affs = realloc(arg->affs, 272 arg->nelements * sizeof (lgrp_affinity_t)); 273 274 if (arg->affs == NULL) { 275 (void) fprintf(stderr, gettext("%s: out of memory\n"), 276 progname); 277 exit(EXIT_FAILURE); 278 } 279 } 280 281 arg->lgrps[arg->nlgrps] = id; 282 arg->affs[arg->nlgrps] = LGRP_AFF_INVALID; 283 arg->nlgrps++; 284 } 285 286 287 /* 288 * Return an array having '1' for each lgroup present in given subtree under 289 * specified lgroup in lgroup hierarchy 290 */ 291 static void 292 lgrps_bitmap_init(lgrp_cookie_t cookie, lgrp_id_t lgrpid, char **bitmap_array, 293 int *bitmap_nelements) 294 { 295 lgrp_id_t *children; 296 int i; 297 int nchildren; 298 299 if (lgrpid < 0) { 300 lgrpid = lgrp_root(cookie); 301 if (lgrpid < 0) 302 return; 303 } 304 305 /* 306 * If new lgroup cannot fit, grow the array and fill unused portion 307 * with zeroes. 308 */ 309 while (lgrpid >= *bitmap_nelements) { 310 *bitmap_nelements += LGRP_BITMAP_CHUNK; 311 *bitmap_array = realloc(*bitmap_array, 312 *bitmap_nelements * sizeof (char)); 313 if (*bitmap_array == NULL) { 314 (void) fprintf(stderr, gettext("%s: out of memory\n"), 315 progname); 316 exit(EXIT_FAILURE); 317 } 318 bzero(*bitmap_array + NLGRPS, 319 (*bitmap_nelements - NLGRPS) * sizeof (char)); 320 } 321 322 /* 323 * Insert lgroup into bitmap and update max lgroup ID seen so far 324 */ 325 (*bitmap_array)[lgrpid] = 1; 326 if (lgrpid > max_lgrpid) 327 max_lgrpid = lgrpid; 328 329 /* 330 * Get children of specified lgroup and insert descendants of each 331 * of them 332 */ 333 nchildren = lgrp_children(cookie, lgrpid, NULL, 0); 334 if (nchildren > 0) { 335 children = malloc(nchildren * sizeof (lgrp_id_t)); 336 if (children == NULL) { 337 (void) fprintf(stderr, gettext("%s: out of memory\n"), 338 progname); 339 exit(EXIT_FAILURE); 340 } 341 if (lgrp_children(cookie, lgrpid, children, nchildren) != 342 nchildren) { 343 free(children); 344 return; 345 } 346 347 for (i = 0; i < nchildren; i++) 348 lgrps_bitmap_init(cookie, children[i], bitmap_array, 349 bitmap_nelements); 350 351 free(children); 352 } 353 } 354 355 356 /* 357 * Parse lgroup affinity from given string 358 * 359 * Return lgroup affinity or LGRP_AFF_INVALID if string doesn't match any 360 * existing lgroup affinity and return pointer to position just after affinity 361 * string. 362 */ 363 static lgrp_affinity_t 364 parse_lgrp_affinity(char *string, char **next) 365 { 366 int rc = LGRP_AFF_INVALID; 367 368 if (string == NULL) 369 return (LGRP_AFF_INVALID); 370 371 /* 372 * Skip delimiter 373 */ 374 if (string[0] == DELIMIT_AFF) 375 string++; 376 377 /* 378 * Return lgroup affinity matching string 379 */ 380 if (strncmp(string, LGRP_AFF_NONE_STR, strlen(LGRP_AFF_NONE_STR)) 381 == 0) { 382 rc = LGRP_AFF_NONE; 383 *next = string + strlen(LGRP_AFF_NONE_STR); 384 } else if (strncmp(string, 385 LGRP_AFF_WEAK_STR, strlen(LGRP_AFF_WEAK_STR)) == 0) { 386 rc = LGRP_AFF_WEAK; 387 *next = string + strlen(LGRP_AFF_WEAK_STR); 388 } else if (strncmp(string, LGRP_AFF_STRONG_STR, 389 strlen(LGRP_AFF_STRONG_STR)) == 0) { 390 rc = LGRP_AFF_STRONG; 391 *next = string + strlen(LGRP_AFF_STRONG_STR); 392 } 393 394 return (rc); 395 } 396 397 398 /* 399 * Parse lgroups from given string 400 * Returns the set containing all lgroups parsed or NULL. 401 */ 402 static int 403 parse_lgrps(lgrp_cookie_t cookie, plgrp_args_t *arg, char *s) 404 { 405 lgrp_id_t i; 406 char *token; 407 408 if (cookie == LGRP_COOKIE_NONE || s == NULL || NLGRPS <= 0) 409 return (0); 410 411 /* 412 * Parse first lgroup (if any) 413 */ 414 token = strtok(s, DELIMIT_LGRP); 415 if (token == NULL) 416 return (-1); 417 418 do { 419 /* 420 * Parse lgroups 421 */ 422 if (isdigit(*token)) { 423 lgrp_id_t first; 424 lgrp_id_t last; 425 char *p; 426 427 /* 428 * lgroup ID(s) 429 * 430 * Can be <lgroup ID>[-<lgroup ID>] 431 */ 432 p = strchr(token, DELIMIT_RANGE); 433 first = atoi(token); 434 if (p == NULL) 435 last = first; 436 else 437 last = atoi(++p); 438 439 for (i = first; i <= last; i++) { 440 /* 441 * Add valid lgroups to lgroup array 442 */ 443 if ((i >= 0) && (i < NLGRPS) && LGRP_VALID(i)) 444 lgrps_add_lgrp(arg, i); 445 else { 446 (void) fprintf(stderr, 447 gettext("%s: bad lgroup %d\n"), 448 progname, i); 449 nerrors++; 450 } 451 } 452 } else if (strncmp(token, LGRP_ALL_STR, 453 strlen(LGRP_ALL_STR)) == 0) { 454 /* 455 * Add "all" lgroups to lgroups array 456 */ 457 for (i = 0; i < NLGRPS; i++) { 458 if (LGRP_VALID(i)) 459 lgrps_add_lgrp(arg, i); 460 } 461 } else if (strncmp(token, LGRP_ROOT_STR, 462 strlen(LGRP_ROOT_STR)) == 0) { 463 if (root < 0) 464 root = lgrp_root(cookie); 465 lgrps_add_lgrp(arg, root); 466 } else if (strncmp(token, LGRP_LEAVES_STR, 467 strlen(LGRP_LEAVES_STR)) == 0) { 468 /* 469 * Add leaf lgroups to lgroups array 470 */ 471 for (i = 0; i < NLGRPS; i++) { 472 if (LGRP_VALID(i) && 473 lgrp_children(cookie, i, NULL, 0) == 0) 474 lgrps_add_lgrp(arg, i); 475 } 476 } else { 477 return (-1); 478 } 479 } while (token = strtok(NULL, DELIMIT_LGRP)); 480 481 return (0); 482 } 483 484 /* 485 * Print array of lgroup IDs, collapsing any consecutive runs of IDs into a 486 * range (eg. 2,3,4 into 2-4) 487 */ 488 static void 489 print_lgrps(lgrp_id_t *lgrps, int nlgrps) 490 { 491 lgrp_id_t start; 492 lgrp_id_t end; 493 int i; 494 495 /* 496 * Initial range consists of the first element 497 */ 498 start = end = lgrps[0]; 499 500 for (i = 1; i < nlgrps; i++) { 501 lgrp_id_t lgrpid; 502 503 lgrpid = lgrps[i]; 504 if (lgrpid == end + 1) { 505 /* 506 * Got consecutive lgroup ID, so extend end of range 507 * without printing anything since the range may extend 508 * further 509 */ 510 end = lgrpid; 511 } else { 512 /* 513 * Next lgroup ID is not consecutive, so print lgroup 514 * IDs gotten so far. 515 */ 516 if (end == start) { /* same value */ 517 (void) printf("%d,", (int)start); 518 } else if (end > start + 1) { /* range */ 519 (void) printf("%d-%d,", (int)start, (int)end); 520 } else { /* different values */ 521 (void) printf("%d,%d,", (int)start, (int)end); 522 } 523 524 /* 525 * Try finding consecutive range starting from this 526 * lgroup ID 527 */ 528 start = end = lgrpid; 529 } 530 } 531 532 /* 533 * Print last lgroup ID(s) 534 */ 535 if (end == start) { 536 (void) printf("%d", (int)start); 537 } else if (end > start + 1) { 538 (void) printf("%d-%d", (int)start, (int)end); 539 } else { 540 (void) printf("%d,%d", (int)start, (int)end); 541 } 542 } 543 544 /* 545 * Print lgroup affinities given array of lgroups, corresponding array of 546 * affinities, and number of elements. 547 * Skip any lgroups set to LGRP_NONE or having invalid affinity. 548 */ 549 static void 550 print_affinities(lgrp_id_t *lgrps, lgrp_affinity_t *affs, int nelements) 551 { 552 int i; 553 lgrp_id_t *lgrps_none; 554 lgrp_id_t *lgrps_strong; 555 lgrp_id_t *lgrps_weak; 556 int nlgrps_none; 557 int nlgrps_strong; 558 int nlgrps_weak; 559 560 nlgrps_strong = nlgrps_weak = nlgrps_none = 0; 561 562 lgrps_strong = malloc(nelements * sizeof (lgrp_id_t)); 563 lgrps_weak = malloc(nelements * sizeof (lgrp_id_t)); 564 lgrps_none = malloc(nelements * sizeof (lgrp_id_t)); 565 566 if (lgrps_strong == NULL || lgrps_weak == NULL || lgrps_none == NULL) { 567 (void) fprintf(stderr, gettext("%s: out of memory\n"), 568 progname); 569 interrupt = 1; 570 return; 571 } 572 573 /* 574 * Group lgroups by affinity 575 */ 576 for (i = 0; i < nelements; i++) { 577 lgrp_id_t lgrpid = lgrps[i]; 578 579 /* 580 * Skip any lgroups set to LGRP_NONE 581 */ 582 if (lgrpid == LGRP_NONE) 583 continue; 584 585 switch (affs[i]) { 586 case LGRP_AFF_STRONG: 587 lgrps_strong[nlgrps_strong++] = lgrpid; 588 break; 589 case LGRP_AFF_WEAK: 590 lgrps_weak[nlgrps_weak++] = lgrpid; 591 break; 592 case LGRP_AFF_NONE: 593 lgrps_none[nlgrps_none++] = lgrpid; 594 break; 595 default: 596 /* 597 * Skip any lgroups with invalid affinity. 598 */ 599 break; 600 } 601 } 602 603 /* 604 * Print all lgroups with same affinity together 605 */ 606 if (nlgrps_strong) { 607 print_lgrps(lgrps_strong, nlgrps_strong); 608 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_STRONG)); 609 if (nlgrps_weak || nlgrps_none) 610 (void) printf("%c", DELIMIT_AFF_LST); 611 } 612 613 if (nlgrps_weak) { 614 print_lgrps(lgrps_weak, nlgrps_weak); 615 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_WEAK)); 616 if (nlgrps_none) 617 (void) printf("%c", DELIMIT_AFF_LST); 618 } 619 620 if (nlgrps_none) { 621 print_lgrps(lgrps_none, nlgrps_none); 622 (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_NONE)); 623 } 624 625 free(lgrps_strong); 626 free(lgrps_weak); 627 free(lgrps_none); 628 } 629 630 631 /* 632 * Print heading for specified operation 633 */ 634 static void 635 print_heading(plgrp_ops_t op) 636 { 637 638 switch (op) { 639 case PLGRP_AFFINITY_GET: 640 (void) printf(HDR_PLGRP_AFF_GET); 641 break; 642 643 case PLGRP_AFFINITY_SET: 644 (void) printf(HDR_PLGRP_AFF_SET); 645 break; 646 647 case PLGRP_HOME_GET: 648 (void) printf(HDR_PLGRP_HOME_GET); 649 break; 650 651 case PLGRP_HOME_SET: 652 (void) printf(HDR_PLGRP_HOME_SET); 653 break; 654 655 default: 656 break; 657 } 658 } 659 660 /* 661 * Use /proc to call lgrp_affinity_get() in another process 662 */ 663 static lgrp_affinity_t 664 Plgrp_affinity_get(struct ps_prochandle *Ph, idtype_t idtype, id_t id, 665 lgrp_id_t lgrp) 666 { 667 lgrp_affinity_args_t args; 668 argdes_t Pargd[3]; 669 argdes_t *Pargdp; 670 int Pnargs; 671 int Pretval; 672 sysret_t retval; 673 int syscall; 674 675 /* 676 * Fill in arguments needed for syscall(SYS_lgrpsys, 677 * LGRP_SYS_AFFINITY_GET, 0, &args) 678 */ 679 syscall = SYS_lgrpsys; 680 681 args.idtype = idtype; 682 args.id = id; 683 args.lgrp = lgrp; 684 args.aff = LGRP_AFF_INVALID; 685 686 /* 687 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys, 688 * LGRP_SYS_AFFINITY_GET, idtype, id) 689 */ 690 Pnargs = LGRPSYS_NARGS; 691 Pargdp = &Pargd[0]; 692 Pargdp->arg_value = LGRP_SYS_AFFINITY_GET; 693 Pargdp->arg_object = NULL; 694 Pargdp->arg_type = AT_BYVAL; 695 Pargdp->arg_inout = AI_INPUT; 696 Pargdp->arg_size = 0; 697 Pargdp++; 698 699 Pargdp->arg_value = 0; 700 Pargdp->arg_object = NULL; 701 Pargdp->arg_type = AT_BYVAL; 702 Pargdp->arg_inout = AI_INPUT; 703 Pargdp->arg_size = 0; 704 Pargdp++; 705 706 Pargdp->arg_value = 0; 707 Pargdp->arg_object = &args; 708 Pargdp->arg_type = AT_BYREF; 709 Pargdp->arg_inout = AI_INPUT; 710 Pargdp->arg_size = sizeof (lgrp_affinity_args_t); 711 Pargdp++; 712 713 /* 714 * Have agent LWP call syscall with appropriate arguments in target 715 * process 716 */ 717 Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]); 718 if (Pretval) { 719 errno = (Pretval < 0) ? ENOSYS : Pretval; 720 return (LGRP_AFF_INVALID); 721 } 722 723 return (retval.sys_rval1); 724 } 725 726 727 /* 728 * Use /proc to call lgrp_affinity_set() in another process 729 */ 730 static int 731 Plgrp_affinity_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id, 732 lgrp_id_t lgrp, lgrp_affinity_t aff) 733 { 734 lgrp_affinity_args_t args; 735 argdes_t Pargd[3]; 736 argdes_t *Pargdp; 737 int Pnargs; 738 int Pretval; 739 sysret_t retval; 740 int syscall; 741 742 /* 743 * Fill in arguments needed for syscall(SYS_lgrpsys, 744 * LGRP_SYS_AFFINITY_SET, 0, &args) 745 */ 746 syscall = SYS_lgrpsys; 747 748 args.idtype = idtype; 749 args.id = id; 750 args.lgrp = lgrp; 751 args.aff = aff; 752 753 /* 754 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys, 755 * LGRP_SYS_AFFINITY_SET, idtype, id) 756 */ 757 Pnargs = LGRPSYS_NARGS; 758 Pargdp = &Pargd[0]; 759 Pargdp->arg_value = LGRP_SYS_AFFINITY_SET; 760 Pargdp->arg_object = NULL; 761 Pargdp->arg_type = AT_BYVAL; 762 Pargdp->arg_inout = AI_INPUT; 763 Pargdp->arg_size = 0; 764 Pargdp++; 765 766 Pargdp->arg_value = 0; 767 Pargdp->arg_object = NULL; 768 Pargdp->arg_type = AT_BYVAL; 769 Pargdp->arg_inout = AI_INPUT; 770 Pargdp->arg_size = 0; 771 Pargdp++; 772 773 Pargdp->arg_value = 0; 774 Pargdp->arg_object = &args; 775 Pargdp->arg_type = AT_BYREF; 776 Pargdp->arg_inout = AI_INPUT; 777 Pargdp->arg_size = sizeof (lgrp_affinity_args_t); 778 Pargdp++; 779 780 /* 781 * Have agent LWP call syscall with appropriate arguments in 782 * target process 783 */ 784 Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]); 785 if (Pretval) { 786 errno = (Pretval < 0) ? ENOSYS : Pretval; 787 return (-1); 788 } 789 790 return (retval.sys_rval1); 791 } 792 793 /* 794 * Use /proc to call lgrp_home() in another process 795 */ 796 static lgrp_id_t 797 Plgrp_home(struct ps_prochandle *Ph, idtype_t idtype, id_t id) 798 { 799 argdes_t Pargd[3]; 800 argdes_t *Pargdp; 801 int Pnargs; 802 int Pretval; 803 sysret_t retval; 804 int syscall; 805 806 /* 807 * Fill in arguments needed for syscall(SYS_lgrpsys, 808 * LGRP_SYS_HOME, idtype, id) 809 */ 810 syscall = SYS_lgrpsys; 811 812 /* 813 * Fill out /proc argument descriptors for syscall(SYS_lgrpsys, 814 * LGRP_SYS_HOME, idtype, id) 815 */ 816 Pnargs = LGRPSYS_NARGS; 817 Pargdp = &Pargd[0]; 818 Pargdp->arg_value = LGRP_SYS_HOME; 819 Pargdp->arg_object = NULL; 820 Pargdp->arg_type = AT_BYVAL; 821 Pargdp->arg_inout = AI_INPUT; 822 Pargdp->arg_size = 0; 823 Pargdp++; 824 825 Pargdp->arg_value = idtype; 826 Pargdp->arg_object = NULL; 827 Pargdp->arg_type = AT_BYVAL; 828 Pargdp->arg_inout = AI_INPUT; 829 Pargdp->arg_size = 0; 830 Pargdp++; 831 832 Pargdp->arg_value = id; 833 Pargdp->arg_object = NULL; 834 Pargdp->arg_type = AT_BYVAL; 835 Pargdp->arg_inout = AI_INPUT; 836 Pargdp->arg_size = 0; 837 Pargdp++; 838 839 /* 840 * Have agent LWP call syscall with appropriate arguments in 841 * target process 842 */ 843 Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]); 844 if (Pretval) { 845 errno = (Pretval < 0) ? ENOSYS : Pretval; 846 return (-1); 847 } 848 849 return (retval.sys_rval1); 850 } 851 852 /* 853 * Use /proc to call lgrp_affinity_set(3LGRP) to set home lgroup of given 854 * thread 855 */ 856 static int 857 Plgrp_home_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id, 858 lgrp_id_t lgrp) 859 { 860 return (Plgrp_affinity_set(Ph, idtype, id, lgrp, 861 LGRP_AFF_STRONG)); 862 } 863 864 865 /* 866 * Do plgrp(1) operation on specified thread 867 */ 868 static int 869 do_op(plgrp_args_t *plgrp_args, id_t pid, id_t lwpid, 870 const lwpsinfo_t *lwpsinfo) 871 { 872 lgrp_affinity_t *affs; 873 lgrp_affinity_t *cur_affs; 874 lgrp_id_t home; 875 int i; 876 lgrp_affinity_t *init_affs; 877 lgrp_id_t *lgrps; 878 lgrp_id_t *lgrps_changed; 879 int nlgrps; 880 lgrp_id_t old_home; 881 lgrp_id_t lgrpid; 882 struct ps_prochandle *Ph; 883 int nchanged; 884 885 /* 886 * No args, so nothing to do. 887 */ 888 if (plgrp_args == NULL) 889 return (0); 890 891 /* 892 * Unpack plgrp(1) arguments and state needed to process this LWP 893 */ 894 Ph = plgrp_args->Ph; 895 lgrps = plgrp_args->lgrps; 896 affs = plgrp_args->affs; 897 nlgrps = plgrp_args->nlgrps; 898 899 switch (plgrp_args->op) { 900 901 case PLGRP_HOME_GET: 902 /* 903 * Get and display home lgroup for given LWP 904 */ 905 home = lwpsinfo->pr_lgrp; 906 (void) printf(FMT_HOME"\n", (int)home); 907 break; 908 909 case PLGRP_AFFINITY_GET: 910 /* 911 * Get and display this LWP's home lgroup and affinities 912 * for specified lgroups 913 */ 914 home = lwpsinfo->pr_lgrp; 915 (void) printf(FMT_HOME, (int)home); 916 917 /* 918 * Collect affinity values 919 */ 920 for (i = 0; i < nlgrps; i++) { 921 affs[i] = Plgrp_affinity_get(Ph, P_LWPID, lwpid, 922 lgrps[i]); 923 924 if (affs[i] == LGRP_AFF_INVALID) { 925 nerrors++; 926 (void) fprintf(stderr, 927 gettext("%s: cannot get affinity" 928 " for lgroup %d for %d/%d: %s\n"), 929 progname, lgrps[i], pid, lwpid, 930 strerror(errno)); 931 } 932 } 933 934 /* 935 * Print affinities for each type. 936 */ 937 print_affinities(lgrps, affs, nlgrps); 938 (void) printf("\n"); 939 940 break; 941 942 case PLGRP_HOME_SET: 943 /* 944 * Get home lgroup before and after setting it and display 945 * change. If more than one lgroup and one LWP are specified, 946 * then home LWPs to lgroups in round robin fashion. 947 */ 948 old_home = lwpsinfo->pr_lgrp; 949 950 i = plgrp_args->index; 951 if (Plgrp_home_set(Ph, P_LWPID, lwpid, lgrps[i]) != 0) { 952 nerrors++; 953 (void) fprintf(stderr, 954 gettext("%s: cannot set home lgroup of %d/%d" 955 " to lgroup %d: %s\n"), 956 progname, pid, lwpid, lgrps[i], 957 strerror(errno)); 958 (void) printf("\n"); 959 } else { 960 int len; 961 int width = strlen(HDR_PLGRP_HOME_CHANGE); 962 963 home = Plgrp_home(Ph, P_LWPID, lwpid); 964 965 if (home < 0) { 966 (void) fprintf(stderr, 967 gettext("%s cannot get home lgroup for" 968 " %d/%d: %s\n"), 969 progname, pid, lwpid, strerror(errno)); 970 nerrors++; 971 } 972 973 len = printf(FMT_NEWHOME, (int)old_home, (int)home); 974 if (len < width) 975 (void) printf("%*c\n", (int)(width - len), ' '); 976 } 977 978 plgrp_args->index = (i + 1) % nlgrps; 979 980 break; 981 982 case PLGRP_AFFINITY_SET: 983 /* 984 * Set affinities for specified lgroups and print old and new 985 * affinities and any resulting change in home lgroups 986 */ 987 988 /* 989 * Get initial home lgroup as it may change. 990 */ 991 old_home = lwpsinfo->pr_lgrp; 992 993 /* 994 * Need to allocate arrays indexed by lgroup (ID) for 995 * affinities and lgroups because user may specify affinity 996 * for same lgroup multiple times.... 997 * 998 * Keeping these arrays by lgroup (ID) eliminates any 999 * duplication and makes it easier to just print initial and 1000 * final lgroup affinities (instead of trying to keep a list 1001 * of lgroups specified which may include duplicates) 1002 */ 1003 init_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t)); 1004 cur_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t)); 1005 lgrps_changed = malloc(NLGRPS * sizeof (lgrp_id_t)); 1006 1007 if (init_affs == NULL || cur_affs == NULL || 1008 lgrps_changed == NULL) { 1009 (void) fprintf(stderr, gettext("%s: out of memory\n"), 1010 progname); 1011 Prelease(Ph, PRELEASE_RETAIN); 1012 if (init_affs != NULL) 1013 free(init_affs); 1014 if (cur_affs != NULL) 1015 free(cur_affs); 1016 nerrors++; 1017 return (EXIT_NONFATAL); 1018 } 1019 1020 /* 1021 * Initialize current and initial lgroup affinities and 1022 * lgroups changed 1023 */ 1024 for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) { 1025 1026 if (!LGRP_VALID(lgrpid)) { 1027 init_affs[lgrpid] = LGRP_AFF_INVALID; 1028 } else { 1029 init_affs[lgrpid] = 1030 Plgrp_affinity_get(Ph, P_LWPID, 1031 lwpid, lgrpid); 1032 1033 if (init_affs[lgrpid] == LGRP_AFF_INVALID) { 1034 nerrors++; 1035 (void) fprintf(stderr, 1036 gettext("%s: cannot get" 1037 " affinity for lgroup %d" 1038 " for %d/%d: %s\n"), 1039 progname, lgrpid, pid, lwpid, 1040 strerror(errno)); 1041 } 1042 } 1043 1044 cur_affs[lgrpid] = init_affs[lgrpid]; 1045 lgrps_changed[lgrpid] = LGRP_NONE; 1046 } 1047 1048 /* 1049 * Change affinities. 1050 */ 1051 for (i = 0; i < nlgrps; i++) { 1052 lgrp_affinity_t aff = affs[i]; 1053 1054 lgrpid = lgrps[i]; 1055 1056 /* 1057 * If the suggested affinity is the same as the current 1058 * one, skip this lgroup. 1059 */ 1060 if (aff == cur_affs[lgrpid]) 1061 continue; 1062 1063 /* 1064 * Set affinity to the new value 1065 */ 1066 if (Plgrp_affinity_set(Ph, P_LWPID, lwpid, lgrpid, 1067 aff) < 0) { 1068 nerrors++; 1069 (void) fprintf(stderr, 1070 gettext("%s: cannot set" 1071 " %s affinity for lgroup %d" 1072 " for %d/%d: %s\n"), 1073 progname, lgrp_affinity_string(aff), 1074 lgrpid, pid, lwpid, 1075 strerror(errno)); 1076 continue; 1077 } 1078 1079 /* 1080 * Get the new value and verify that it changed as 1081 * expected. 1082 */ 1083 cur_affs[lgrpid] = 1084 Plgrp_affinity_get(Ph, P_LWPID, lwpid, lgrpid); 1085 1086 if (cur_affs[lgrpid] == LGRP_AFF_INVALID) { 1087 nerrors++; 1088 (void) fprintf(stderr, 1089 gettext("%s: cannot get" 1090 " affinity for lgroup %d" 1091 " for %d/%d: %s\n"), 1092 progname, lgrpid, pid, lwpid, 1093 strerror(errno)); 1094 continue; 1095 } 1096 1097 if (aff != cur_affs[lgrpid]) { 1098 (void) fprintf(stderr, 1099 gettext("%s: affinity for" 1100 " lgroup %d is set to %d instead of %d" 1101 " for %d/%d\n"), 1102 progname, lgrpid, cur_affs[lgrpid], aff, 1103 pid, lwpid); 1104 nerrors++; 1105 } 1106 } 1107 1108 /* 1109 * Compare current and initial affinities and mark lgroups with 1110 * changed affinities. 1111 */ 1112 nchanged = 0; 1113 for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) { 1114 if (init_affs[lgrpid] != cur_affs[lgrpid]) { 1115 lgrps_changed[lgrpid] = lgrpid; 1116 nchanged++; 1117 } 1118 } 1119 1120 if (nchanged == 0) { 1121 /* 1122 * Nothing changed, so just print current affinities for 1123 * specified lgroups. 1124 */ 1125 for (i = 0; i < nlgrps; i++) { 1126 lgrps_changed[lgrps[i]] = lgrps[i]; 1127 } 1128 1129 (void) printf("%-*d", 1130 (int)strlen(HDR_PLGRP_HOME_CHANGE), 1131 (int)old_home); 1132 1133 print_affinities(lgrps_changed, cur_affs, NLGRPS); 1134 (void) printf("\n"); 1135 } else { 1136 int width = strlen(HDR_PLGRP_HOME_CHANGE); 1137 1138 /* 1139 * Some lgroup affinities changed, so display old 1140 * and new home lgroups for thread and its old and new 1141 * affinities for affected lgroups 1142 */ 1143 home = Plgrp_home(Ph, P_LWPID, lwpid); 1144 if (home < 0) { 1145 (void) fprintf(stderr, 1146 gettext("%s: cannot get home" 1147 " for %d/%d: %s\n"), 1148 progname, pid, lwpid, strerror(errno)); 1149 nerrors++; 1150 } 1151 if (old_home != home) { 1152 int len; 1153 1154 /* 1155 * Fit string into fixed width 1156 */ 1157 len = printf(FMT_NEWHOME, 1158 (int)old_home, (int)home); 1159 if (len < width) 1160 (void) printf("%*c", width - len, ' '); 1161 } else { 1162 (void) printf("%-*d", width, (int)home); 1163 } 1164 1165 /* 1166 * Print change in affinities from old to new 1167 */ 1168 print_affinities(lgrps_changed, init_affs, NLGRPS); 1169 (void) printf(" => "); 1170 print_affinities(lgrps_changed, cur_affs, NLGRPS); 1171 (void) printf("\n"); 1172 } 1173 1174 free(lgrps_changed); 1175 free(init_affs); 1176 free(cur_affs); 1177 1178 break; 1179 1180 default: 1181 break; 1182 } 1183 1184 return (0); 1185 } 1186 1187 1188 /* 1189 * Routine called by Plwp_iter_all() as it iterates through LWPs of another 1190 * process 1191 */ 1192 /* ARGSUSED */ 1193 static int 1194 Plwp_iter_handler(void *arg, const lwpstatus_t *lwpstatus, 1195 const lwpsinfo_t *lwpsinfo) 1196 { 1197 id_t lwpid; 1198 struct ps_prochandle *Ph; 1199 const pstatus_t *pstatus; 1200 plgrp_args_t *plgrp_args; 1201 1202 /* 1203 * Nothing to do if no arguments 1204 */ 1205 if (arg == NULL || interrupt) 1206 return (0); 1207 1208 /* 1209 * Unpack plgrp(1) arguments and state needed to process this LWP 1210 */ 1211 plgrp_args = arg; 1212 Ph = plgrp_args->Ph; 1213 1214 /* 1215 * Just return if no /proc handle for process 1216 */ 1217 if (Ph == NULL) 1218 return (0); 1219 1220 pstatus = Pstatus(Ph); 1221 1222 /* 1223 * Skip agent LWP and any LWPs that weren't specified 1224 */ 1225 lwpid = lwpsinfo->pr_lwpid; 1226 if (lwpid == pstatus->pr_agentid || 1227 !proc_lwp_in_set(plgrp_args->lwps, lwpid)) 1228 return (0); 1229 1230 plgrp_args->nthreads++; 1231 1232 /* 1233 * Do all plgrp(1) operations specified on given thread 1234 */ 1235 (void) printf(FMT_THREAD" ", (int)pstatus->pr_pid, (int)lwpid); 1236 return (do_op(plgrp_args, pstatus->pr_pid, lwpid, lwpsinfo)); 1237 } 1238 1239 /* 1240 * Get target process specified in "pidstring" argument to do operation(s) 1241 * specified in "plgrp_todo" using /proc and agent LWP 1242 */ 1243 static void 1244 do_process(char *pidstring, plgrp_args_t *plgrp_todo, int force) 1245 { 1246 int error; 1247 const char *lwps; 1248 struct ps_prochandle *Ph; 1249 1250 /* 1251 * Nothing to do, so return. 1252 */ 1253 if (plgrp_todo == NULL || interrupt) 1254 return; 1255 1256 /* 1257 * Grab target process or core and return 1258 * /proc handle for process and string of LWP 1259 * IDs 1260 */ 1261 Ph = proc_arg_xgrab(pidstring, NULL, 1262 PR_ARG_ANY, force | PGRAB_RETAIN | PGRAB_NOSTOP, &error, &lwps); 1263 if (Ph == NULL) { 1264 (void) fprintf(stderr, 1265 gettext("%s: Unable to grab process %s: %s\n"), 1266 progname, pidstring, Pgrab_error(error)); 1267 nerrors++; 1268 return; 1269 } 1270 1271 /* 1272 * Fill in remaining plgrp(1) arguments and state needed to do 1273 * plgrp(1) operation(s) on desired LWPs in our handler 1274 * called by Plwp_iter_all() as it iterates over LWPs 1275 * in given process 1276 */ 1277 plgrp_todo->Ph = Ph; 1278 plgrp_todo->lwps = lwps; 1279 1280 /* 1281 * Iterate over LWPs in process and do specified 1282 * operation(s) on those specified 1283 */ 1284 if (Plwp_iter_all(Ph, Plwp_iter_handler, plgrp_todo) != 0) { 1285 (void) fprintf(stderr, 1286 gettext("%s: error iterating over threads\n"), 1287 progname); 1288 nerrors++; 1289 } 1290 1291 Prelease(Ph, PRELEASE_RETAIN); 1292 } 1293 1294 1295 /* 1296 * Parse command line and kick off any resulting actions 1297 * 1298 * plgrp(1) has the following command line syntax: 1299 * 1300 * plgrp [-h] <pid> | <core> [/lwps] ... 1301 * plgrp [-F] -a <lgroup>,... <pid>[/lwps] ... 1302 * plgrp [-F] -H <lgroup>,... <pid>[/lwps] ... 1303 * plgrp [-F] -A <lgroup>,... [/none|weak|strong] ... <pid>[/lwps] ... 1304 * 1305 * where <lgroup> is an lgroup ID, "all", "root", "leaves". 1306 */ 1307 int 1308 main(int argc, char *argv[]) 1309 { 1310 lgrp_affinity_t aff; 1311 char *affstring; 1312 int c; 1313 lgrp_cookie_t cookie; 1314 int Fflag; 1315 int i; 1316 int opt_seen; 1317 plgrp_args_t plgrp_todo; 1318 char *s; 1319 1320 (void) setlocale(LC_ALL, ""); 1321 (void) textdomain(TEXT_DOMAIN); 1322 1323 opt_seen = 0; 1324 1325 /* 1326 * Get name of program 1327 */ 1328 progname = basename(argv[0]); 1329 1330 /* 1331 * Not much to do when only name of program given 1332 */ 1333 if (argc == 1) 1334 usage(0); 1335 1336 /* 1337 * Catch signals from terminal, so they can be handled asynchronously 1338 * when we're ready instead of when we're not (;-) 1339 */ 1340 if (sigset(SIGHUP, SIG_IGN) == SIG_DFL) 1341 (void) sigset(SIGHUP, intr); 1342 if (sigset(SIGINT, SIG_IGN) == SIG_DFL) 1343 (void) sigset(SIGINT, intr); 1344 if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL) 1345 (void) sigset(SIGQUIT, intr); 1346 (void) sigset(SIGPIPE, intr); 1347 (void) sigset(SIGTERM, intr); 1348 1349 /* 1350 * Take snapshot of lgroup hierarchy 1351 */ 1352 cookie = lgrp_init(LGRP_VIEW_OS); 1353 if (cookie == LGRP_COOKIE_NONE) { 1354 (void) fprintf(stderr, 1355 gettext("%s: Fatal error: cannot get lgroup" 1356 " information from the OS: %s\n"), 1357 progname, strerror(errno)); 1358 return (EXIT_FAILURE); 1359 } 1360 1361 root = lgrp_root(cookie); 1362 lgrps_bitmap_init(cookie, root, &lgrps_bitmap, &lgrps_bitmap_nelements); 1363 1364 /* 1365 * Remember arguments and state needed to do plgrp(1) operation 1366 * on desired LWPs 1367 */ 1368 bzero(&plgrp_todo, sizeof (plgrp_args_t)); 1369 plgrp_todo.op = PLGRP_HOME_GET; 1370 1371 /* 1372 * Parse options 1373 */ 1374 opterr = 0; 1375 Fflag = 0; 1376 while (!interrupt && (c = getopt(argc, argv, "a:A:FhH:")) != -1) { 1377 /* 1378 * Parse option and only allow one option besides -F to be 1379 * specified 1380 */ 1381 switch (c) { 1382 1383 case 'h': /* Get home lgroup */ 1384 /* 1385 * Only allow one option (besides -F) to be specified 1386 */ 1387 if (opt_seen) 1388 usage(EXIT_FAILURE); 1389 opt_seen = 1; 1390 1391 plgrp_todo.op = PLGRP_HOME_GET; 1392 break; 1393 1394 case 'H': /* Set home lgroup */ 1395 1396 /* 1397 * Fail if already specified option (besides -F) 1398 * or no more arguments 1399 */ 1400 if (opt_seen || optind >= argc) { 1401 usage(EXIT_FAILURE); 1402 } 1403 opt_seen = 1; 1404 1405 plgrp_todo.op = PLGRP_HOME_SET; 1406 1407 if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0) 1408 usage(EXIT_FAILURE); 1409 1410 /* If there are no valid lgroups exit immediately */ 1411 if (plgrp_todo.nlgrps == 0) { 1412 (void) fprintf(stderr, 1413 gettext("%s: no valid lgroups" 1414 " specified for -%c\n\n"), 1415 progname, c); 1416 usage(EXIT_FAILURE); 1417 } 1418 1419 break; 1420 1421 case 'a': /* Get lgroup affinity */ 1422 1423 /* 1424 * Fail if already specified option (besides -F) 1425 * or no more arguments 1426 */ 1427 if (opt_seen || optind >= argc) { 1428 usage(EXIT_FAILURE); 1429 } 1430 opt_seen = 1; 1431 1432 plgrp_todo.op = PLGRP_AFFINITY_GET; 1433 1434 if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0) 1435 usage(EXIT_FAILURE); 1436 1437 /* If there are no valid lgroups exit immediately */ 1438 if (plgrp_todo.nlgrps == 0) { 1439 (void) fprintf(stderr, 1440 gettext("%s: no valid lgroups specified" 1441 " for -%c\n\n"), 1442 progname, c); 1443 usage(EXIT_FAILURE); 1444 } 1445 1446 break; 1447 1448 case 'A': /* Set lgroup affinity */ 1449 1450 /* 1451 * Fail if already specified option (besides -F) 1452 * or no more arguments 1453 */ 1454 if (opt_seen || optind >= argc) { 1455 usage(EXIT_FAILURE); 1456 } 1457 opt_seen = 1; 1458 1459 plgrp_todo.op = PLGRP_AFFINITY_SET; 1460 1461 /* 1462 * 'affstring' is the unparsed prtion of the affinity 1463 * specification like 1,2/none,2/weak,0/strong 1464 * 1465 * 'next' is the next affinity specification to parse. 1466 */ 1467 affstring = optarg; 1468 while (affstring != NULL && strlen(affstring) > 0) { 1469 char *next; 1470 1471 /* 1472 * affstring points to the first affinity 1473 * specification. Split the string by 1474 * DELIMIT_AFF separator and parse lgroups and 1475 * affinity value separately. 1476 */ 1477 s = strchr(affstring, DELIMIT_AFF); 1478 if (s == NULL) { 1479 (void) fprintf(stderr, 1480 gettext("%s: invalid " 1481 "syntax >%s<\n"), 1482 progname, affstring); 1483 usage(EXIT_FAILURE); 1484 } 1485 1486 aff = parse_lgrp_affinity(s, &next); 1487 if (aff == LGRP_AFF_INVALID) { 1488 (void) fprintf(stderr, 1489 gettext("%s: invalid " 1490 "affinity >%s<\n"), 1491 progname, affstring); 1492 usage(EXIT_FAILURE); 1493 } 1494 1495 /* 1496 * next should either point to the empty string 1497 * or to the DELIMIT_AFF_LST separator. 1498 */ 1499 if (*next != '\0') { 1500 if (*next != DELIMIT_AFF_LST) { 1501 (void) fprintf(stderr, 1502 gettext("%s: invalid " 1503 "syntax >%s<\n"), 1504 progname, next); 1505 usage(EXIT_FAILURE); 1506 } 1507 *next = '\0'; 1508 next++; 1509 } 1510 1511 1512 /* 1513 * Now parse the list of lgroups 1514 */ 1515 if (parse_lgrps(cookie, &plgrp_todo, 1516 affstring) < 0) { 1517 usage(EXIT_FAILURE); 1518 } 1519 1520 /* 1521 * Set desired affinity for specified lgroup to 1522 * the specified affinity. 1523 */ 1524 for (i = 0; i < plgrp_todo.nlgrps; i++) { 1525 if (plgrp_todo.affs[i] == 1526 LGRP_AFF_INVALID) 1527 plgrp_todo.affs[i] = aff; 1528 } 1529 1530 /* 1531 * We processed the leftmost element of the 1532 * list. Advance affstr to the remaining part of 1533 * the list. and repeat. 1534 */ 1535 affstring = next; 1536 } 1537 1538 /* 1539 * If there are no valid lgroups, exit immediately 1540 */ 1541 if (plgrp_todo.nlgrps == 0) { 1542 (void) fprintf(stderr, 1543 gettext("%s: no valid lgroups specified " 1544 "for -%c\n\n"), progname, c); 1545 usage(EXIT_FAILURE); 1546 } 1547 1548 break; 1549 1550 case 'F': /* Force */ 1551 1552 /* 1553 * Only allow one occurrence 1554 */ 1555 if (Fflag != 0) { 1556 usage(EXIT_FAILURE); 1557 } 1558 1559 /* 1560 * Set flag to force /proc to grab process even though 1561 * it's been grabbed by another process already 1562 */ 1563 Fflag = PGRAB_FORCE; 1564 break; 1565 1566 case '?': /* Unrecognized option */ 1567 default: 1568 usage(EXIT_FAILURE); 1569 break; 1570 1571 } 1572 } 1573 1574 /* 1575 * Should have more arguments left at least for PID or core 1576 */ 1577 if (optind >= argc) 1578 usage(EXIT_FAILURE); 1579 1580 (void) lgrp_fini(cookie); 1581 1582 /* 1583 * Print heading and process each [pid | core]/lwps argument 1584 */ 1585 print_heading(plgrp_todo.op); 1586 (void) proc_initstdio(); 1587 1588 for (i = optind; i < argc && !interrupt; i++) { 1589 (void) proc_flushstdio(); 1590 do_process(argv[i], &plgrp_todo, Fflag); 1591 } 1592 1593 (void) proc_finistdio(); 1594 1595 if (plgrp_todo.nthreads == 0) { 1596 (void) fprintf(stderr, gettext("%s: no matching LWPs found\n"), 1597 progname); 1598 } 1599 1600 return ((nerrors ||interrupt) ? EXIT_NONFATAL : EXIT_SUCCESS); 1601 } 1602