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