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