12685Sakolb /*
22685Sakolb * CDDL HEADER START
32685Sakolb *
42685Sakolb * The contents of this file are subject to the terms of the
52685Sakolb * Common Development and Distribution License (the "License").
62685Sakolb * You may not use this file except in compliance with the License.
72685Sakolb *
82685Sakolb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92685Sakolb * or http://www.opensolaris.org/os/licensing.
102685Sakolb * See the License for the specific language governing permissions
112685Sakolb * and limitations under the License.
122685Sakolb *
132685Sakolb * When distributing Covered Code, include this CDDL HEADER in each
142685Sakolb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152685Sakolb * If applicable, add the following below this CDDL HEADER, with the
162685Sakolb * fields enclosed by brackets "[]" replaced with your own identifying
172685Sakolb * information: Portions Copyright [yyyy] [name of copyright owner]
182685Sakolb *
192685Sakolb * CDDL HEADER END
202685Sakolb */
212685Sakolb
222685Sakolb /*
23*7032Sakolb * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
242685Sakolb * Use is subject to license terms.
252685Sakolb */
262685Sakolb
272685Sakolb #pragma ident "%Z%%M% %I% %E% SMI"
282685Sakolb
292685Sakolb /*
302685Sakolb * The plgrp utility allows a user to display and modify the home lgroup and
312685Sakolb * lgroup affinities of the specified threads
322685Sakolb */
332685Sakolb
342685Sakolb #include <ctype.h>
352685Sakolb #include <errno.h>
362685Sakolb #include <libintl.h>
372685Sakolb #include <libproc.h>
382685Sakolb #include <locale.h>
392685Sakolb #include <signal.h>
402685Sakolb #include <stdio.h>
412685Sakolb #include <stdlib.h>
422685Sakolb #include <strings.h>
432685Sakolb #include <unistd.h>
442685Sakolb #include <libgen.h>
452685Sakolb #include <sys/lgrp_user.h>
462685Sakolb
472685Sakolb
482685Sakolb /*
492685Sakolb * Delimiters
502685Sakolb */
512685Sakolb #define DELIMIT_AFF '/' /* lgroup affinity from lgroups */
522685Sakolb #define DELIMIT_LGRP "," /* lgroups from each other */
532685Sakolb #define DELIMIT_LWP "/" /* thread/LWP IDs from process ID */
542685Sakolb #define DELIMIT_RANGE '-' /* range of IDs (eg. lgroup) */
552685Sakolb #define DELIMIT_AFF_LST ',' /* list of affinities from another list */
562685Sakolb
572685Sakolb /*
582685Sakolb * Exit values other than EXIT_{SUCCESS,FAILURE}
592685Sakolb */
602685Sakolb #define EXIT_NONFATAL 2 /* non-fatal errors */
612685Sakolb
622685Sakolb /*
632685Sakolb * Header and format strings
642685Sakolb */
652685Sakolb #define HDR_PLGRP_AFF_GET " PID/LWPID HOME AFFINITY\n"
662685Sakolb #define HDR_PLGRP_AFF_SET " PID/LWPID HOME AFFINITY\n"
672685Sakolb #define HDR_PLGRP_HOME_GET " PID/LWPID HOME\n"
682685Sakolb #define HDR_PLGRP_HOME_SET " PID/LWPID HOME\n"
692685Sakolb
702685Sakolb /*
712685Sakolb * Part of the HDR_PLGRP_AFF_SET header used to calculate space needed to
722685Sakolb * represent changing home as old => new
732685Sakolb */
742685Sakolb #define HDR_PLGRP_HOME_CHANGE "HOME "
752685Sakolb
762685Sakolb #define FMT_AFF "%d/%s"
772685Sakolb #define FMT_AFF_STR "%s"
782685Sakolb #define FMT_HOME "%-6d"
792685Sakolb #define FMT_NEWHOME "%d => %d"
802685Sakolb #define FMT_THREAD "%8d/%-8d"
812685Sakolb
822685Sakolb /*
832685Sakolb * How much to allocate for lgroup bitmap array as it grows
842685Sakolb */
852685Sakolb #define LGRP_BITMAP_CHUNK 8
862685Sakolb
872685Sakolb /*
882685Sakolb * Strings that can be given for lgroups
892685Sakolb */
902685Sakolb #define LGRP_ALL_STR "all"
912685Sakolb #define LGRP_LEAVES_STR "leaves"
922685Sakolb #define LGRP_ROOT_STR "root"
932685Sakolb
942685Sakolb /*
952685Sakolb * Strings corresponding to lgroup affinities
962685Sakolb */
972685Sakolb #define LGRP_AFF_NONE_STR "none"
982685Sakolb #define LGRP_AFF_STRONG_STR "strong"
992685Sakolb #define LGRP_AFF_WEAK_STR "weak"
1002685Sakolb
1012685Sakolb /*
1022685Sakolb * Invalid value for lgroup affinity
1032685Sakolb */
1042685Sakolb #define LGRP_AFF_INVALID -1
1052685Sakolb
1062685Sakolb /*
1072685Sakolb * Number of args needed for lgroup system call
1082685Sakolb */
1092685Sakolb #define LGRPSYS_NARGS 3
1102685Sakolb
1112685Sakolb #ifndef TEXT_DOMAIN /* should be defined by cc -D */
1122685Sakolb #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
1132685Sakolb #endif
1142685Sakolb
1152685Sakolb /*
1162685Sakolb * plgrp(1) operations
1172685Sakolb */
1182685Sakolb typedef enum plgrp_ops {
1192685Sakolb PLGRP_AFFINITY_GET,
1202685Sakolb PLGRP_AFFINITY_SET,
1212685Sakolb PLGRP_HOME_GET,
1222685Sakolb PLGRP_HOME_SET,
1232685Sakolb PLGRP_NO_OP
1242685Sakolb } plgrp_ops_t;
1252685Sakolb
1262685Sakolb /*
1272685Sakolb * Arguments specified to plgrp(1) and any state needed to do everything
1282685Sakolb * that plgrp(1) does for one operation from inside Plwp_iter_all()
1292685Sakolb */
1302685Sakolb typedef struct plgrp_args {
1312685Sakolb struct ps_prochandle *Ph; /* proc handle for process */
1322685Sakolb const char *lwps; /* LWPs */
1332685Sakolb lgrp_id_t *lgrps; /* lgroups */
1342685Sakolb lgrp_affinity_t *affs; /* lgroup affinities */
1352685Sakolb int nlgrps; /* number of lgroups */
1362685Sakolb int nelements; /* number of elements */
1372685Sakolb int index; /* index */
1382685Sakolb int nthreads; /* threads processed */
1392685Sakolb plgrp_ops_t op; /* operation */
1402685Sakolb } plgrp_args_t;
1412685Sakolb
1422685Sakolb /*
1432685Sakolb * How many signals caught from terminal
1442685Sakolb * We bail out as soon as possible when interrupt is set
1452685Sakolb */
1462685Sakolb static int interrupt = 0;
1472685Sakolb
1482685Sakolb /*
1492685Sakolb * How many non-fatal errors ocurred
1502685Sakolb */
1512685Sakolb static int nerrors = 0;
1522685Sakolb
1532685Sakolb /*
1542685Sakolb * Name of this program
1552685Sakolb */
1562685Sakolb static char *progname;
1572685Sakolb
1582685Sakolb /*
1592685Sakolb * Root of the lgroup hierarchy
1602685Sakolb */
1612685Sakolb static lgrp_id_t root = LGRP_NONE;
1622685Sakolb
1632685Sakolb /*
1642685Sakolb * Bitmap of all lgroups in the system
1652685Sakolb */
1662685Sakolb static char *lgrps_bitmap = NULL;
1672685Sakolb
1682685Sakolb /*
1692685Sakolb * Size of lgrps_bitmap array
1702685Sakolb */
1712685Sakolb static int lgrps_bitmap_nelements = 0;
1722685Sakolb
1732685Sakolb /*
1742685Sakolb * Macro LGRP_VALID returns true when lgrp is present in the system.
1752685Sakolb */
1762685Sakolb #define LGRP_VALID(lgrp) (lgrps_bitmap[lgrp] != 0)
1772685Sakolb
1782685Sakolb
1792685Sakolb /*
1802685Sakolb * Maximum lgroup value.
1812685Sakolb */
1822685Sakolb static int max_lgrpid = LGRP_NONE;
1832685Sakolb
1842685Sakolb /*
1852685Sakolb * Total possible number of lgroups
1862685Sakolb */
1872685Sakolb #define NLGRPS (max_lgrpid + 1)
1882685Sakolb
1892685Sakolb
1902685Sakolb static void
usage(int rc)1912685Sakolb usage(int rc)
1922685Sakolb {
1932685Sakolb (void) fprintf(stderr,
1942685Sakolb gettext("Usage:\t%s [-h] <pid> | <core> [/lwps] ...\n"), progname);
1952685Sakolb (void) fprintf(stderr,
1962685Sakolb gettext("\t%s [-F] -a <lgroup list> <pid>[/lwps] ...\n"), progname);
1972685Sakolb (void) fprintf(stderr,
1982685Sakolb gettext("\t%s [-F] -A <lgroup list>/none|weak|strong[,...] "
1992685Sakolb " <pid>[/lwps] ...\n"), progname);
2002685Sakolb (void) fprintf(stderr,
2012685Sakolb gettext("\t%s [-F] -H <lgroup list> <pid>[/lwps] ...\n"), progname);
2022685Sakolb (void) fprintf(stderr,
2032685Sakolb gettext("\n\twhere <lgroup list> is a comma separated list of\n"
2042685Sakolb "\tone or more of the following:\n\n"
2052685Sakolb "\t - lgroup ID\n"
2062685Sakolb "\t - Range of lgroup IDs specified as\n"
2072685Sakolb "\t\t<start lgroup ID>-<end lgroup ID>\n"
2082685Sakolb "\t - \"all\"\n"
2092685Sakolb "\t - \"root\"\n"
2102685Sakolb "\t - \"leaves\"\n\n"));
2112685Sakolb
2122685Sakolb exit(rc);
2132685Sakolb }
2142685Sakolb
2152685Sakolb /*
2162685Sakolb * Handler for catching signals from terminal
2172685Sakolb */
2182685Sakolb /* ARGSUSED */
2192685Sakolb static void
intr(int sig)2202685Sakolb intr(int sig)
2212685Sakolb {
2222685Sakolb interrupt++;
2232685Sakolb }
2242685Sakolb
2252685Sakolb
2262685Sakolb /*
2272685Sakolb * Return string name for given lgroup affinity
2282685Sakolb */
2292685Sakolb static char *
lgrp_affinity_string(lgrp_affinity_t aff)2302685Sakolb lgrp_affinity_string(lgrp_affinity_t aff)
2312685Sakolb {
2322685Sakolb char *rc = "unknown";
2332685Sakolb
2342685Sakolb switch (aff) {
2352685Sakolb case LGRP_AFF_STRONG:
2362685Sakolb rc = "strong";
2372685Sakolb break;
2382685Sakolb case LGRP_AFF_WEAK:
2392685Sakolb rc = "weak";
2402685Sakolb break;
2412685Sakolb case LGRP_AFF_NONE:
2422685Sakolb rc = "none";
2432685Sakolb break;
2442685Sakolb default:
2452685Sakolb break;
2462685Sakolb }
2472685Sakolb
2482685Sakolb return (rc);
2492685Sakolb }
2502685Sakolb
2512685Sakolb
2522685Sakolb /*
2532685Sakolb * Add a new lgroup into lgroup array in "arg", growing lgroup and affinity
2542685Sakolb * arrays if necessary
2552685Sakolb */
2562685Sakolb static void
lgrps_add_lgrp(plgrp_args_t * arg,int id)2572685Sakolb lgrps_add_lgrp(plgrp_args_t *arg, int id)
2582685Sakolb {
2592685Sakolb
2602685Sakolb if (arg->nlgrps == arg->nelements) {
2612685Sakolb arg->nelements += LGRP_BITMAP_CHUNK;
2622685Sakolb
2632685Sakolb arg->lgrps = realloc(arg->lgrps,
2642685Sakolb arg->nelements * sizeof (lgrp_id_t));
2652685Sakolb if (arg->lgrps == NULL) {
2662685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
2672685Sakolb progname);
2682685Sakolb exit(EXIT_FAILURE);
2692685Sakolb }
2702685Sakolb
2712685Sakolb arg->affs = realloc(arg->affs,
2722685Sakolb arg->nelements * sizeof (lgrp_affinity_t));
2732685Sakolb
2742685Sakolb if (arg->affs == NULL) {
2752685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
2762685Sakolb progname);
2772685Sakolb exit(EXIT_FAILURE);
2782685Sakolb }
2792685Sakolb }
2802685Sakolb
2812685Sakolb arg->lgrps[arg->nlgrps] = id;
2822685Sakolb arg->affs[arg->nlgrps] = LGRP_AFF_INVALID;
2832685Sakolb arg->nlgrps++;
2842685Sakolb }
2852685Sakolb
2862685Sakolb
2872685Sakolb /*
2882685Sakolb * Return an array having '1' for each lgroup present in given subtree under
2892685Sakolb * specified lgroup in lgroup hierarchy
2902685Sakolb */
2912685Sakolb static void
lgrps_bitmap_init(lgrp_cookie_t cookie,lgrp_id_t lgrpid,char ** bitmap_array,int * bitmap_nelements)2922685Sakolb lgrps_bitmap_init(lgrp_cookie_t cookie, lgrp_id_t lgrpid, char **bitmap_array,
2932685Sakolb int *bitmap_nelements)
2942685Sakolb {
2952685Sakolb lgrp_id_t *children;
2962685Sakolb int i;
2972685Sakolb int nchildren;
2982685Sakolb
2992685Sakolb if (lgrpid < 0) {
3002685Sakolb lgrpid = lgrp_root(cookie);
3012685Sakolb if (lgrpid < 0)
3022685Sakolb return;
3032685Sakolb }
3042685Sakolb
3052685Sakolb /*
3062685Sakolb * If new lgroup cannot fit, grow the array and fill unused portion
3072685Sakolb * with zeroes.
3082685Sakolb */
3092685Sakolb while (lgrpid >= *bitmap_nelements) {
3102685Sakolb *bitmap_nelements += LGRP_BITMAP_CHUNK;
3112685Sakolb *bitmap_array = realloc(*bitmap_array,
3122685Sakolb *bitmap_nelements * sizeof (char));
3132685Sakolb if (*bitmap_array == NULL) {
3142685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
3152685Sakolb progname);
3162685Sakolb exit(EXIT_FAILURE);
3172685Sakolb }
3182685Sakolb bzero(*bitmap_array + NLGRPS,
3192685Sakolb (*bitmap_nelements - NLGRPS) * sizeof (char));
3202685Sakolb }
3212685Sakolb
3222685Sakolb /*
3232685Sakolb * Insert lgroup into bitmap and update max lgroup ID seen so far
3242685Sakolb */
3252685Sakolb (*bitmap_array)[lgrpid] = 1;
3262685Sakolb if (lgrpid > max_lgrpid)
3272685Sakolb max_lgrpid = lgrpid;
3282685Sakolb
3292685Sakolb /*
3302685Sakolb * Get children of specified lgroup and insert descendants of each
3312685Sakolb * of them
3322685Sakolb */
3332685Sakolb nchildren = lgrp_children(cookie, lgrpid, NULL, 0);
3342685Sakolb if (nchildren > 0) {
3352685Sakolb children = malloc(nchildren * sizeof (lgrp_id_t));
3362685Sakolb if (children == NULL) {
3372685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
3382685Sakolb progname);
3392685Sakolb exit(EXIT_FAILURE);
3402685Sakolb }
3412685Sakolb if (lgrp_children(cookie, lgrpid, children, nchildren) !=
3422685Sakolb nchildren) {
3432685Sakolb free(children);
3442685Sakolb return;
3452685Sakolb }
3462685Sakolb
3472685Sakolb for (i = 0; i < nchildren; i++)
3482685Sakolb lgrps_bitmap_init(cookie, children[i], bitmap_array,
3492685Sakolb bitmap_nelements);
3502685Sakolb
3512685Sakolb free(children);
3522685Sakolb }
3532685Sakolb }
3542685Sakolb
3552685Sakolb
3562685Sakolb /*
3572685Sakolb * Parse lgroup affinity from given string
3582685Sakolb *
3592685Sakolb * Return lgroup affinity or LGRP_AFF_INVALID if string doesn't match any
3602685Sakolb * existing lgroup affinity and return pointer to position just after affinity
3612685Sakolb * string.
3622685Sakolb */
3632685Sakolb static lgrp_affinity_t
parse_lgrp_affinity(char * string,char ** next)3642685Sakolb parse_lgrp_affinity(char *string, char **next)
3652685Sakolb {
3662685Sakolb int rc = LGRP_AFF_INVALID;
3672685Sakolb
3682685Sakolb if (string == NULL)
3692685Sakolb return (LGRP_AFF_INVALID);
3702685Sakolb
3712685Sakolb /*
3722685Sakolb * Skip delimiter
3732685Sakolb */
3742685Sakolb if (string[0] == DELIMIT_AFF)
3752685Sakolb string++;
3762685Sakolb
3772685Sakolb /*
3782685Sakolb * Return lgroup affinity matching string
3792685Sakolb */
3802685Sakolb if (strncmp(string, LGRP_AFF_NONE_STR, strlen(LGRP_AFF_NONE_STR))
3812685Sakolb == 0) {
3822685Sakolb rc = LGRP_AFF_NONE;
3832685Sakolb *next = string + strlen(LGRP_AFF_NONE_STR);
3842685Sakolb } else if (strncmp(string,
3852685Sakolb LGRP_AFF_WEAK_STR, strlen(LGRP_AFF_WEAK_STR)) == 0) {
3862685Sakolb rc = LGRP_AFF_WEAK;
3872685Sakolb *next = string + strlen(LGRP_AFF_WEAK_STR);
3882685Sakolb } else if (strncmp(string, LGRP_AFF_STRONG_STR,
3892685Sakolb strlen(LGRP_AFF_STRONG_STR)) == 0) {
3902685Sakolb rc = LGRP_AFF_STRONG;
3912685Sakolb *next = string + strlen(LGRP_AFF_STRONG_STR);
3922685Sakolb }
3932685Sakolb
3942685Sakolb return (rc);
3952685Sakolb }
3962685Sakolb
3972685Sakolb
3982685Sakolb /*
3992685Sakolb * Parse lgroups from given string
4002685Sakolb * Returns the set containing all lgroups parsed or NULL.
4012685Sakolb */
4022685Sakolb static int
parse_lgrps(lgrp_cookie_t cookie,plgrp_args_t * arg,char * s)4032685Sakolb parse_lgrps(lgrp_cookie_t cookie, plgrp_args_t *arg, char *s)
4042685Sakolb {
4052685Sakolb lgrp_id_t i;
4062685Sakolb char *token;
4072685Sakolb
4082685Sakolb if (cookie == LGRP_COOKIE_NONE || s == NULL || NLGRPS <= 0)
4092685Sakolb return (0);
4102685Sakolb
4112685Sakolb /*
4122685Sakolb * Parse first lgroup (if any)
4132685Sakolb */
4142685Sakolb token = strtok(s, DELIMIT_LGRP);
4152685Sakolb if (token == NULL)
4162685Sakolb return (-1);
4172685Sakolb
4182685Sakolb do {
4192685Sakolb /*
4202685Sakolb * Parse lgroups
4212685Sakolb */
4222685Sakolb if (isdigit(*token)) {
4232685Sakolb lgrp_id_t first;
4242685Sakolb lgrp_id_t last;
4252685Sakolb char *p;
4262685Sakolb
4272685Sakolb /*
4282685Sakolb * lgroup ID(s)
4292685Sakolb *
4302685Sakolb * Can be <lgroup ID>[-<lgroup ID>]
4312685Sakolb */
4322685Sakolb p = strchr(token, DELIMIT_RANGE);
4332685Sakolb first = atoi(token);
4342685Sakolb if (p == NULL)
4352685Sakolb last = first;
4362685Sakolb else
4372685Sakolb last = atoi(++p);
4382685Sakolb
4392685Sakolb for (i = first; i <= last; i++) {
4402685Sakolb /*
4412685Sakolb * Add valid lgroups to lgroup array
4422685Sakolb */
4432685Sakolb if ((i >= 0) && (i < NLGRPS) && LGRP_VALID(i))
4442685Sakolb lgrps_add_lgrp(arg, i);
4452685Sakolb else {
4462685Sakolb (void) fprintf(stderr,
4472685Sakolb gettext("%s: bad lgroup %d\n"),
4482685Sakolb progname, i);
4492685Sakolb nerrors++;
4502685Sakolb }
4512685Sakolb }
4522685Sakolb } else if (strncmp(token, LGRP_ALL_STR,
4532685Sakolb strlen(LGRP_ALL_STR)) == 0) {
4542685Sakolb /*
4552685Sakolb * Add "all" lgroups to lgroups array
4562685Sakolb */
4572685Sakolb for (i = 0; i < NLGRPS; i++) {
4582685Sakolb if (LGRP_VALID(i))
4592685Sakolb lgrps_add_lgrp(arg, i);
4602685Sakolb }
4612685Sakolb } else if (strncmp(token, LGRP_ROOT_STR,
4622685Sakolb strlen(LGRP_ROOT_STR)) == 0) {
4632685Sakolb if (root < 0)
4642685Sakolb root = lgrp_root(cookie);
4652685Sakolb lgrps_add_lgrp(arg, root);
4662685Sakolb } else if (strncmp(token, LGRP_LEAVES_STR,
4672685Sakolb strlen(LGRP_LEAVES_STR)) == 0) {
4682685Sakolb /*
4692685Sakolb * Add leaf lgroups to lgroups array
4702685Sakolb */
4712685Sakolb for (i = 0; i < NLGRPS; i++) {
4722685Sakolb if (LGRP_VALID(i) &&
4732685Sakolb lgrp_children(cookie, i, NULL, 0) == 0)
4742685Sakolb lgrps_add_lgrp(arg, i);
4752685Sakolb }
4762685Sakolb } else {
4772685Sakolb return (-1);
4782685Sakolb }
4792685Sakolb } while (token = strtok(NULL, DELIMIT_LGRP));
4802685Sakolb
4812685Sakolb return (0);
4822685Sakolb }
4832685Sakolb
4842685Sakolb /*
4852685Sakolb * Print array of lgroup IDs, collapsing any consecutive runs of IDs into a
4862685Sakolb * range (eg. 2,3,4 into 2-4)
4872685Sakolb */
4882685Sakolb static void
print_lgrps(lgrp_id_t * lgrps,int nlgrps)4892685Sakolb print_lgrps(lgrp_id_t *lgrps, int nlgrps)
4902685Sakolb {
4912685Sakolb lgrp_id_t start;
4922685Sakolb lgrp_id_t end;
4932685Sakolb int i;
4942685Sakolb
4952685Sakolb /*
4962685Sakolb * Initial range consists of the first element
4972685Sakolb */
4982685Sakolb start = end = lgrps[0];
4992685Sakolb
5002685Sakolb for (i = 1; i < nlgrps; i++) {
5012685Sakolb lgrp_id_t lgrpid;
5022685Sakolb
5032685Sakolb lgrpid = lgrps[i];
5042685Sakolb if (lgrpid == end + 1) {
5052685Sakolb /*
5062685Sakolb * Got consecutive lgroup ID, so extend end of range
5072685Sakolb * without printing anything since the range may extend
5082685Sakolb * further
5092685Sakolb */
5102685Sakolb end = lgrpid;
5112685Sakolb } else {
5122685Sakolb /*
5132685Sakolb * Next lgroup ID is not consecutive, so print lgroup
5142685Sakolb * IDs gotten so far.
5152685Sakolb */
5162685Sakolb if (end == start) { /* same value */
5172685Sakolb (void) printf("%d,", (int)start);
5182685Sakolb } else if (end > start + 1) { /* range */
5192685Sakolb (void) printf("%d-%d,", (int)start, (int)end);
5202685Sakolb } else { /* different values */
5212685Sakolb (void) printf("%d,%d,", (int)start, (int)end);
5222685Sakolb }
5232685Sakolb
5242685Sakolb /*
5252685Sakolb * Try finding consecutive range starting from this
5262685Sakolb * lgroup ID
5272685Sakolb */
5282685Sakolb start = end = lgrpid;
5292685Sakolb }
5302685Sakolb }
5312685Sakolb
5322685Sakolb /*
5332685Sakolb * Print last lgroup ID(s)
5342685Sakolb */
5352685Sakolb if (end == start) {
5362685Sakolb (void) printf("%d", (int)start);
5372685Sakolb } else if (end > start + 1) {
5382685Sakolb (void) printf("%d-%d", (int)start, (int)end);
5392685Sakolb } else {
5402685Sakolb (void) printf("%d,%d", (int)start, (int)end);
5412685Sakolb }
5422685Sakolb }
5432685Sakolb
5442685Sakolb /*
5452685Sakolb * Print lgroup affinities given array of lgroups, corresponding array of
5462685Sakolb * affinities, and number of elements.
5472685Sakolb * Skip any lgroups set to LGRP_NONE or having invalid affinity.
5482685Sakolb */
5492685Sakolb static void
print_affinities(lgrp_id_t * lgrps,lgrp_affinity_t * affs,int nelements)5502685Sakolb print_affinities(lgrp_id_t *lgrps, lgrp_affinity_t *affs, int nelements)
5512685Sakolb {
5522685Sakolb int i;
5532685Sakolb lgrp_id_t *lgrps_none;
5542685Sakolb lgrp_id_t *lgrps_strong;
5552685Sakolb lgrp_id_t *lgrps_weak;
5562685Sakolb int nlgrps_none;
5572685Sakolb int nlgrps_strong;
5582685Sakolb int nlgrps_weak;
5592685Sakolb
5602685Sakolb nlgrps_strong = nlgrps_weak = nlgrps_none = 0;
5612685Sakolb
5622685Sakolb lgrps_strong = malloc(nelements * sizeof (lgrp_id_t));
5632685Sakolb lgrps_weak = malloc(nelements * sizeof (lgrp_id_t));
5642685Sakolb lgrps_none = malloc(nelements * sizeof (lgrp_id_t));
5652685Sakolb
5662685Sakolb if (lgrps_strong == NULL || lgrps_weak == NULL || lgrps_none == NULL) {
5672685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
5682685Sakolb progname);
5692685Sakolb interrupt = 1;
5702685Sakolb return;
5712685Sakolb }
5722685Sakolb
5732685Sakolb /*
5742685Sakolb * Group lgroups by affinity
5752685Sakolb */
5762685Sakolb for (i = 0; i < nelements; i++) {
5772685Sakolb lgrp_id_t lgrpid = lgrps[i];
5782685Sakolb
5792685Sakolb /*
5802685Sakolb * Skip any lgroups set to LGRP_NONE
5812685Sakolb */
5822685Sakolb if (lgrpid == LGRP_NONE)
5832685Sakolb continue;
5842685Sakolb
5852685Sakolb switch (affs[i]) {
5862685Sakolb case LGRP_AFF_STRONG:
5872685Sakolb lgrps_strong[nlgrps_strong++] = lgrpid;
5882685Sakolb break;
5892685Sakolb case LGRP_AFF_WEAK:
5902685Sakolb lgrps_weak[nlgrps_weak++] = lgrpid;
5912685Sakolb break;
5922685Sakolb case LGRP_AFF_NONE:
5932685Sakolb lgrps_none[nlgrps_none++] = lgrpid;
5942685Sakolb break;
5952685Sakolb default:
5962685Sakolb /*
5972685Sakolb * Skip any lgroups with invalid affinity.
5982685Sakolb */
5992685Sakolb break;
6002685Sakolb }
6012685Sakolb }
6022685Sakolb
6032685Sakolb /*
6042685Sakolb * Print all lgroups with same affinity together
6052685Sakolb */
6062685Sakolb if (nlgrps_strong) {
6072685Sakolb print_lgrps(lgrps_strong, nlgrps_strong);
6082685Sakolb (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_STRONG));
6092685Sakolb if (nlgrps_weak || nlgrps_none)
6102685Sakolb (void) printf("%c", DELIMIT_AFF_LST);
6112685Sakolb }
6122685Sakolb
6132685Sakolb if (nlgrps_weak) {
6142685Sakolb print_lgrps(lgrps_weak, nlgrps_weak);
6152685Sakolb (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_WEAK));
6162685Sakolb if (nlgrps_none)
6172685Sakolb (void) printf("%c", DELIMIT_AFF_LST);
6182685Sakolb }
6192685Sakolb
6202685Sakolb if (nlgrps_none) {
6212685Sakolb print_lgrps(lgrps_none, nlgrps_none);
6222685Sakolb (void) printf("/%s", lgrp_affinity_string(LGRP_AFF_NONE));
6232685Sakolb }
6242685Sakolb
6252685Sakolb free(lgrps_strong);
6262685Sakolb free(lgrps_weak);
6272685Sakolb free(lgrps_none);
6282685Sakolb }
6292685Sakolb
6302685Sakolb
6312685Sakolb /*
6322685Sakolb * Print heading for specified operation
6332685Sakolb */
6342685Sakolb static void
print_heading(plgrp_ops_t op)6352685Sakolb print_heading(plgrp_ops_t op)
6362685Sakolb {
6372685Sakolb
6382685Sakolb switch (op) {
6392685Sakolb case PLGRP_AFFINITY_GET:
6402685Sakolb (void) printf(HDR_PLGRP_AFF_GET);
6412685Sakolb break;
6422685Sakolb
6432685Sakolb case PLGRP_AFFINITY_SET:
6442685Sakolb (void) printf(HDR_PLGRP_AFF_SET);
6452685Sakolb break;
6462685Sakolb
6472685Sakolb case PLGRP_HOME_GET:
6482685Sakolb (void) printf(HDR_PLGRP_HOME_GET);
6492685Sakolb break;
6502685Sakolb
6512685Sakolb case PLGRP_HOME_SET:
6522685Sakolb (void) printf(HDR_PLGRP_HOME_SET);
6532685Sakolb break;
6542685Sakolb
6552685Sakolb default:
6562685Sakolb break;
6572685Sakolb }
6582685Sakolb }
6592685Sakolb
6602685Sakolb /*
6612685Sakolb * Use /proc to call lgrp_affinity_get() in another process
6622685Sakolb */
6632685Sakolb static lgrp_affinity_t
Plgrp_affinity_get(struct ps_prochandle * Ph,idtype_t idtype,id_t id,lgrp_id_t lgrp)6642685Sakolb Plgrp_affinity_get(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
6652685Sakolb lgrp_id_t lgrp)
6662685Sakolb {
6672685Sakolb lgrp_affinity_args_t args;
6682685Sakolb argdes_t Pargd[3];
6692685Sakolb argdes_t *Pargdp;
6702685Sakolb int Pnargs;
6712685Sakolb int Pretval;
6722685Sakolb sysret_t retval;
6732685Sakolb int syscall;
6742685Sakolb
6752685Sakolb /*
6762685Sakolb * Fill in arguments needed for syscall(SYS_lgrpsys,
6772685Sakolb * LGRP_SYS_AFFINITY_GET, 0, &args)
6782685Sakolb */
6792685Sakolb syscall = SYS_lgrpsys;
6802685Sakolb
6812685Sakolb args.idtype = idtype;
6822685Sakolb args.id = id;
6832685Sakolb args.lgrp = lgrp;
6842685Sakolb args.aff = LGRP_AFF_INVALID;
6852685Sakolb
6862685Sakolb /*
6872685Sakolb * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
6882685Sakolb * LGRP_SYS_AFFINITY_GET, idtype, id)
6892685Sakolb */
6902685Sakolb Pnargs = LGRPSYS_NARGS;
6912685Sakolb Pargdp = &Pargd[0];
6922685Sakolb Pargdp->arg_value = LGRP_SYS_AFFINITY_GET;
6932685Sakolb Pargdp->arg_object = NULL;
6942685Sakolb Pargdp->arg_type = AT_BYVAL;
6952685Sakolb Pargdp->arg_inout = AI_INPUT;
6962685Sakolb Pargdp->arg_size = 0;
6972685Sakolb Pargdp++;
6982685Sakolb
6992685Sakolb Pargdp->arg_value = 0;
7002685Sakolb Pargdp->arg_object = NULL;
7012685Sakolb Pargdp->arg_type = AT_BYVAL;
7022685Sakolb Pargdp->arg_inout = AI_INPUT;
7032685Sakolb Pargdp->arg_size = 0;
7042685Sakolb Pargdp++;
7052685Sakolb
7062685Sakolb Pargdp->arg_value = 0;
7072685Sakolb Pargdp->arg_object = &args;
7082685Sakolb Pargdp->arg_type = AT_BYREF;
7092685Sakolb Pargdp->arg_inout = AI_INPUT;
7102685Sakolb Pargdp->arg_size = sizeof (lgrp_affinity_args_t);
7112685Sakolb Pargdp++;
7122685Sakolb
7132685Sakolb /*
7142685Sakolb * Have agent LWP call syscall with appropriate arguments in target
7152685Sakolb * process
7162685Sakolb */
7172685Sakolb Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
7182685Sakolb if (Pretval) {
7192685Sakolb errno = (Pretval < 0) ? ENOSYS : Pretval;
7202685Sakolb return (LGRP_AFF_INVALID);
7212685Sakolb }
7222685Sakolb
7232685Sakolb return (retval.sys_rval1);
7242685Sakolb }
7252685Sakolb
7262685Sakolb
7272685Sakolb /*
7282685Sakolb * Use /proc to call lgrp_affinity_set() in another process
7292685Sakolb */
7302685Sakolb static int
Plgrp_affinity_set(struct ps_prochandle * Ph,idtype_t idtype,id_t id,lgrp_id_t lgrp,lgrp_affinity_t aff)7312685Sakolb Plgrp_affinity_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
7322685Sakolb lgrp_id_t lgrp, lgrp_affinity_t aff)
7332685Sakolb {
7342685Sakolb lgrp_affinity_args_t args;
7352685Sakolb argdes_t Pargd[3];
7362685Sakolb argdes_t *Pargdp;
7372685Sakolb int Pnargs;
7382685Sakolb int Pretval;
7392685Sakolb sysret_t retval;
7402685Sakolb int syscall;
7412685Sakolb
7422685Sakolb /*
7432685Sakolb * Fill in arguments needed for syscall(SYS_lgrpsys,
7442685Sakolb * LGRP_SYS_AFFINITY_SET, 0, &args)
7452685Sakolb */
7462685Sakolb syscall = SYS_lgrpsys;
7472685Sakolb
7482685Sakolb args.idtype = idtype;
7492685Sakolb args.id = id;
7502685Sakolb args.lgrp = lgrp;
7512685Sakolb args.aff = aff;
7522685Sakolb
7532685Sakolb /*
7542685Sakolb * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
7552685Sakolb * LGRP_SYS_AFFINITY_SET, idtype, id)
7562685Sakolb */
7572685Sakolb Pnargs = LGRPSYS_NARGS;
7582685Sakolb Pargdp = &Pargd[0];
7592685Sakolb Pargdp->arg_value = LGRP_SYS_AFFINITY_SET;
7602685Sakolb Pargdp->arg_object = NULL;
7612685Sakolb Pargdp->arg_type = AT_BYVAL;
7622685Sakolb Pargdp->arg_inout = AI_INPUT;
7632685Sakolb Pargdp->arg_size = 0;
7642685Sakolb Pargdp++;
7652685Sakolb
7662685Sakolb Pargdp->arg_value = 0;
7672685Sakolb Pargdp->arg_object = NULL;
7682685Sakolb Pargdp->arg_type = AT_BYVAL;
7692685Sakolb Pargdp->arg_inout = AI_INPUT;
7702685Sakolb Pargdp->arg_size = 0;
7712685Sakolb Pargdp++;
7722685Sakolb
7732685Sakolb Pargdp->arg_value = 0;
7742685Sakolb Pargdp->arg_object = &args;
7752685Sakolb Pargdp->arg_type = AT_BYREF;
7762685Sakolb Pargdp->arg_inout = AI_INPUT;
7772685Sakolb Pargdp->arg_size = sizeof (lgrp_affinity_args_t);
7782685Sakolb Pargdp++;
7792685Sakolb
7802685Sakolb /*
7812685Sakolb * Have agent LWP call syscall with appropriate arguments in
7822685Sakolb * target process
7832685Sakolb */
7842685Sakolb Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
7852685Sakolb if (Pretval) {
7862685Sakolb errno = (Pretval < 0) ? ENOSYS : Pretval;
7872685Sakolb return (-1);
7882685Sakolb }
7892685Sakolb
7902685Sakolb return (retval.sys_rval1);
7912685Sakolb }
7922685Sakolb
7932685Sakolb /*
7942685Sakolb * Use /proc to call lgrp_home() in another process
7952685Sakolb */
7962685Sakolb static lgrp_id_t
Plgrp_home(struct ps_prochandle * Ph,idtype_t idtype,id_t id)7972685Sakolb Plgrp_home(struct ps_prochandle *Ph, idtype_t idtype, id_t id)
7982685Sakolb {
7992685Sakolb argdes_t Pargd[3];
8002685Sakolb argdes_t *Pargdp;
8012685Sakolb int Pnargs;
8022685Sakolb int Pretval;
8032685Sakolb sysret_t retval;
8042685Sakolb int syscall;
8052685Sakolb
8062685Sakolb /*
8072685Sakolb * Fill in arguments needed for syscall(SYS_lgrpsys,
8082685Sakolb * LGRP_SYS_HOME, idtype, id)
8092685Sakolb */
8102685Sakolb syscall = SYS_lgrpsys;
8112685Sakolb
8122685Sakolb /*
8132685Sakolb * Fill out /proc argument descriptors for syscall(SYS_lgrpsys,
8142685Sakolb * LGRP_SYS_HOME, idtype, id)
8152685Sakolb */
8162685Sakolb Pnargs = LGRPSYS_NARGS;
8172685Sakolb Pargdp = &Pargd[0];
8182685Sakolb Pargdp->arg_value = LGRP_SYS_HOME;
8192685Sakolb Pargdp->arg_object = NULL;
8202685Sakolb Pargdp->arg_type = AT_BYVAL;
8212685Sakolb Pargdp->arg_inout = AI_INPUT;
8222685Sakolb Pargdp->arg_size = 0;
8232685Sakolb Pargdp++;
8242685Sakolb
8252685Sakolb Pargdp->arg_value = idtype;
8262685Sakolb Pargdp->arg_object = NULL;
8272685Sakolb Pargdp->arg_type = AT_BYVAL;
8282685Sakolb Pargdp->arg_inout = AI_INPUT;
8292685Sakolb Pargdp->arg_size = 0;
8302685Sakolb Pargdp++;
8312685Sakolb
8322685Sakolb Pargdp->arg_value = id;
8332685Sakolb Pargdp->arg_object = NULL;
8342685Sakolb Pargdp->arg_type = AT_BYVAL;
8352685Sakolb Pargdp->arg_inout = AI_INPUT;
8362685Sakolb Pargdp->arg_size = 0;
8372685Sakolb Pargdp++;
8382685Sakolb
8392685Sakolb /*
8402685Sakolb * Have agent LWP call syscall with appropriate arguments in
8412685Sakolb * target process
8422685Sakolb */
8432685Sakolb Pretval = Psyscall(Ph, &retval, syscall, Pnargs, &Pargd[0]);
8442685Sakolb if (Pretval) {
8452685Sakolb errno = (Pretval < 0) ? ENOSYS : Pretval;
8462685Sakolb return (-1);
8472685Sakolb }
8482685Sakolb
8492685Sakolb return (retval.sys_rval1);
8502685Sakolb }
8512685Sakolb
8522685Sakolb /*
8532685Sakolb * Use /proc to call lgrp_affinity_set(3LGRP) to set home lgroup of given
8542685Sakolb * thread
8552685Sakolb */
8562685Sakolb static int
Plgrp_home_set(struct ps_prochandle * Ph,idtype_t idtype,id_t id,lgrp_id_t lgrp)8572685Sakolb Plgrp_home_set(struct ps_prochandle *Ph, idtype_t idtype, id_t id,
8582685Sakolb lgrp_id_t lgrp)
8592685Sakolb {
8602685Sakolb return (Plgrp_affinity_set(Ph, idtype, id, lgrp,
8612685Sakolb LGRP_AFF_STRONG));
8622685Sakolb }
8632685Sakolb
8642685Sakolb
8652685Sakolb /*
8662685Sakolb * Do plgrp(1) operation on specified thread
8672685Sakolb */
8682685Sakolb static int
do_op(plgrp_args_t * plgrp_args,id_t pid,id_t lwpid,const lwpsinfo_t * lwpsinfo)8692685Sakolb do_op(plgrp_args_t *plgrp_args, id_t pid, id_t lwpid,
8702685Sakolb const lwpsinfo_t *lwpsinfo)
8712685Sakolb {
8722685Sakolb lgrp_affinity_t *affs;
8732685Sakolb lgrp_affinity_t *cur_affs;
8742685Sakolb lgrp_id_t home;
8752685Sakolb int i;
8762685Sakolb lgrp_affinity_t *init_affs;
8772685Sakolb lgrp_id_t *lgrps;
8782685Sakolb lgrp_id_t *lgrps_changed;
8792685Sakolb int nlgrps;
8802685Sakolb lgrp_id_t old_home;
8812685Sakolb lgrp_id_t lgrpid;
8822685Sakolb struct ps_prochandle *Ph;
8832685Sakolb int nchanged;
8842685Sakolb
8852685Sakolb /*
8862685Sakolb * No args, so nothing to do.
8872685Sakolb */
8882685Sakolb if (plgrp_args == NULL)
8892685Sakolb return (0);
8902685Sakolb
8912685Sakolb /*
8922685Sakolb * Unpack plgrp(1) arguments and state needed to process this LWP
8932685Sakolb */
8942685Sakolb Ph = plgrp_args->Ph;
8952685Sakolb lgrps = plgrp_args->lgrps;
8962685Sakolb affs = plgrp_args->affs;
8972685Sakolb nlgrps = plgrp_args->nlgrps;
8982685Sakolb
8992685Sakolb switch (plgrp_args->op) {
9002685Sakolb
9012685Sakolb case PLGRP_HOME_GET:
9022685Sakolb /*
9032685Sakolb * Get and display home lgroup for given LWP
9042685Sakolb */
9052685Sakolb home = lwpsinfo->pr_lgrp;
9062685Sakolb (void) printf(FMT_HOME"\n", (int)home);
9072685Sakolb break;
9082685Sakolb
9092685Sakolb case PLGRP_AFFINITY_GET:
9102685Sakolb /*
9112685Sakolb * Get and display this LWP's home lgroup and affinities
9122685Sakolb * for specified lgroups
9132685Sakolb */
9142685Sakolb home = lwpsinfo->pr_lgrp;
9152685Sakolb (void) printf(FMT_HOME, (int)home);
9162685Sakolb
9172685Sakolb /*
9182685Sakolb * Collect affinity values
9192685Sakolb */
9202685Sakolb for (i = 0; i < nlgrps; i++) {
9212685Sakolb affs[i] = Plgrp_affinity_get(Ph, P_LWPID, lwpid,
9222685Sakolb lgrps[i]);
9232685Sakolb
9242685Sakolb if (affs[i] == LGRP_AFF_INVALID) {
9252685Sakolb nerrors++;
9262685Sakolb (void) fprintf(stderr,
9272685Sakolb gettext("%s: cannot get affinity"
9282685Sakolb " for lgroup %d for %d/%d: %s\n"),
9292685Sakolb progname, lgrps[i], pid, lwpid,
9302685Sakolb strerror(errno));
9312685Sakolb }
9322685Sakolb }
9332685Sakolb
9342685Sakolb /*
9352685Sakolb * Print affinities for each type.
9362685Sakolb */
9372685Sakolb print_affinities(lgrps, affs, nlgrps);
9382685Sakolb (void) printf("\n");
9392685Sakolb
9402685Sakolb break;
9412685Sakolb
9422685Sakolb case PLGRP_HOME_SET:
9432685Sakolb /*
9442685Sakolb * Get home lgroup before and after setting it and display
9452685Sakolb * change. If more than one lgroup and one LWP are specified,
9462685Sakolb * then home LWPs to lgroups in round robin fashion.
9472685Sakolb */
9482685Sakolb old_home = lwpsinfo->pr_lgrp;
9492685Sakolb
9502685Sakolb i = plgrp_args->index;
9512685Sakolb if (Plgrp_home_set(Ph, P_LWPID, lwpid, lgrps[i]) != 0) {
9522685Sakolb nerrors++;
9532685Sakolb (void) fprintf(stderr,
9542685Sakolb gettext("%s: cannot set home lgroup of %d/%d"
9552685Sakolb " to lgroup %d: %s\n"),
9562685Sakolb progname, pid, lwpid, lgrps[i],
9572685Sakolb strerror(errno));
9582685Sakolb (void) printf("\n");
9592685Sakolb } else {
9602685Sakolb int len;
9612685Sakolb int width = strlen(HDR_PLGRP_HOME_CHANGE);
9622685Sakolb
9632685Sakolb home = Plgrp_home(Ph, P_LWPID, lwpid);
9642685Sakolb
9652685Sakolb if (home < 0) {
9662685Sakolb (void) fprintf(stderr,
9672685Sakolb gettext("%s cannot get home lgroup for"
9682685Sakolb " %d/%d: %s\n"),
9692685Sakolb progname, pid, lwpid, strerror(errno));
9702685Sakolb nerrors++;
9712685Sakolb }
9722685Sakolb
9732685Sakolb len = printf(FMT_NEWHOME, (int)old_home, (int)home);
9742685Sakolb if (len < width)
9752685Sakolb (void) printf("%*c\n", (int)(width - len), ' ');
9762685Sakolb }
9772685Sakolb
9782685Sakolb plgrp_args->index = (i + 1) % nlgrps;
9792685Sakolb
9802685Sakolb break;
9812685Sakolb
9822685Sakolb case PLGRP_AFFINITY_SET:
9832685Sakolb /*
9842685Sakolb * Set affinities for specified lgroups and print old and new
9852685Sakolb * affinities and any resulting change in home lgroups
9862685Sakolb */
9872685Sakolb
9882685Sakolb /*
9892685Sakolb * Get initial home lgroup as it may change.
9902685Sakolb */
9912685Sakolb old_home = lwpsinfo->pr_lgrp;
9922685Sakolb
9932685Sakolb /*
9942685Sakolb * Need to allocate arrays indexed by lgroup (ID) for
9952685Sakolb * affinities and lgroups because user may specify affinity
9962685Sakolb * for same lgroup multiple times....
9972685Sakolb *
9982685Sakolb * Keeping these arrays by lgroup (ID) eliminates any
9992685Sakolb * duplication and makes it easier to just print initial and
10002685Sakolb * final lgroup affinities (instead of trying to keep a list
10012685Sakolb * of lgroups specified which may include duplicates)
10022685Sakolb */
10032685Sakolb init_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t));
10042685Sakolb cur_affs = malloc(NLGRPS * sizeof (lgrp_affinity_t));
10052685Sakolb lgrps_changed = malloc(NLGRPS * sizeof (lgrp_id_t));
10062685Sakolb
10072685Sakolb if (init_affs == NULL || cur_affs == NULL ||
10082685Sakolb lgrps_changed == NULL) {
10092685Sakolb (void) fprintf(stderr, gettext("%s: out of memory\n"),
10102685Sakolb progname);
10112685Sakolb Prelease(Ph, PRELEASE_RETAIN);
1012*7032Sakolb if (init_affs != NULL)
1013*7032Sakolb free(init_affs);
1014*7032Sakolb if (cur_affs != NULL)
1015*7032Sakolb free(cur_affs);
1016*7032Sakolb nerrors++;
1017*7032Sakolb return (EXIT_NONFATAL);
10182685Sakolb }
10192685Sakolb
10202685Sakolb /*
10212685Sakolb * Initialize current and initial lgroup affinities and
10222685Sakolb * lgroups changed
10232685Sakolb */
10242685Sakolb for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) {
10252685Sakolb
10262685Sakolb if (!LGRP_VALID(lgrpid)) {
10272685Sakolb init_affs[lgrpid] = LGRP_AFF_INVALID;
10282685Sakolb } else {
10292685Sakolb init_affs[lgrpid] =
10302685Sakolb Plgrp_affinity_get(Ph, P_LWPID,
10312685Sakolb lwpid, lgrpid);
10322685Sakolb
10332685Sakolb if (init_affs[lgrpid] == LGRP_AFF_INVALID) {
10342685Sakolb nerrors++;
10352685Sakolb (void) fprintf(stderr,
10362685Sakolb gettext("%s: cannot get"
10372685Sakolb " affinity for lgroup %d"
10382685Sakolb " for %d/%d: %s\n"),
10392685Sakolb progname, lgrpid, pid, lwpid,
10402685Sakolb strerror(errno));
10412685Sakolb }
10422685Sakolb }
10432685Sakolb
10442685Sakolb cur_affs[lgrpid] = init_affs[lgrpid];
10452685Sakolb lgrps_changed[lgrpid] = LGRP_NONE;
10462685Sakolb }
10472685Sakolb
10482685Sakolb /*
10492685Sakolb * Change affinities.
10502685Sakolb */
10512685Sakolb for (i = 0; i < nlgrps; i++) {
10522685Sakolb lgrp_affinity_t aff = affs[i];
10532685Sakolb
10542685Sakolb lgrpid = lgrps[i];
10552685Sakolb
10562685Sakolb /*
10572685Sakolb * If the suggested affinity is the same as the current
10582685Sakolb * one, skip this lgroup.
10592685Sakolb */
10602685Sakolb if (aff == cur_affs[lgrpid])
10612685Sakolb continue;
10622685Sakolb
10632685Sakolb /*
10642685Sakolb * Set affinity to the new value
10652685Sakolb */
10662685Sakolb if (Plgrp_affinity_set(Ph, P_LWPID, lwpid, lgrpid,
10672685Sakolb aff) < 0) {
10682685Sakolb nerrors++;
10692685Sakolb (void) fprintf(stderr,
10702685Sakolb gettext("%s: cannot set"
10712685Sakolb " %s affinity for lgroup %d"
10722685Sakolb " for %d/%d: %s\n"),
10732685Sakolb progname, lgrp_affinity_string(aff),
10742685Sakolb lgrpid, pid, lwpid,
10752685Sakolb strerror(errno));
10762685Sakolb continue;
10772685Sakolb }
10782685Sakolb
10792685Sakolb /*
10802685Sakolb * Get the new value and verify that it changed as
10812685Sakolb * expected.
10822685Sakolb */
10832685Sakolb cur_affs[lgrpid] =
10842685Sakolb Plgrp_affinity_get(Ph, P_LWPID, lwpid, lgrpid);
10852685Sakolb
10862685Sakolb if (cur_affs[lgrpid] == LGRP_AFF_INVALID) {
10872685Sakolb nerrors++;
10882685Sakolb (void) fprintf(stderr,
10892685Sakolb gettext("%s: cannot get"
10902685Sakolb " affinity for lgroup %d"
10912685Sakolb " for %d/%d: %s\n"),
10922685Sakolb progname, lgrpid, pid, lwpid,
10932685Sakolb strerror(errno));
10942685Sakolb continue;
10952685Sakolb }
10962685Sakolb
10972685Sakolb if (aff != cur_affs[lgrpid]) {
10982685Sakolb (void) fprintf(stderr,
10992685Sakolb gettext("%s: affinity for"
11002685Sakolb " lgroup %d is set to %d instead of %d"
11012685Sakolb " for %d/%d\n"),
11022685Sakolb progname, lgrpid, cur_affs[lgrpid], aff,
11032685Sakolb pid, lwpid);
11042685Sakolb nerrors++;
11052685Sakolb }
11062685Sakolb }
11072685Sakolb
11082685Sakolb /*
11092685Sakolb * Compare current and initial affinities and mark lgroups with
11102685Sakolb * changed affinities.
11112685Sakolb */
11122685Sakolb nchanged = 0;
11132685Sakolb for (lgrpid = 0; lgrpid < NLGRPS; lgrpid++) {
11142685Sakolb if (init_affs[lgrpid] != cur_affs[lgrpid]) {
11152685Sakolb lgrps_changed[lgrpid] = lgrpid;
11162685Sakolb nchanged++;
11172685Sakolb }
11182685Sakolb }
11192685Sakolb
11202685Sakolb if (nchanged == 0) {
11212685Sakolb /*
11222685Sakolb * Nothing changed, so just print current affinities for
11232685Sakolb * specified lgroups.
11242685Sakolb */
11252685Sakolb for (i = 0; i < nlgrps; i++) {
11262685Sakolb lgrps_changed[lgrps[i]] = lgrps[i];
11272685Sakolb }
11282685Sakolb
11292685Sakolb (void) printf("%-*d",
11302685Sakolb (int)strlen(HDR_PLGRP_HOME_CHANGE),
11312685Sakolb (int)old_home);
11322685Sakolb
11332685Sakolb print_affinities(lgrps_changed, cur_affs, NLGRPS);
11342685Sakolb (void) printf("\n");
11352685Sakolb } else {
11362685Sakolb int width = strlen(HDR_PLGRP_HOME_CHANGE);
11372685Sakolb
11382685Sakolb /*
11392685Sakolb * Some lgroup affinities changed, so display old
11402685Sakolb * and new home lgroups for thread and its old and new
11412685Sakolb * affinities for affected lgroups
11422685Sakolb */
11432685Sakolb home = Plgrp_home(Ph, P_LWPID, lwpid);
11442685Sakolb if (home < 0) {
11452685Sakolb (void) fprintf(stderr,
11462685Sakolb gettext("%s: cannot get home"
11472685Sakolb " for %d/%d: %s\n"),
11482685Sakolb progname, pid, lwpid, strerror(errno));
11492685Sakolb nerrors++;
11502685Sakolb }
11512685Sakolb if (old_home != home) {
11522685Sakolb int len;
11532685Sakolb
11542685Sakolb /*
11552685Sakolb * Fit string into fixed width
11562685Sakolb */
11572685Sakolb len = printf(FMT_NEWHOME,
11582685Sakolb (int)old_home, (int)home);
11592685Sakolb if (len < width)
11602685Sakolb (void) printf("%*c", width - len, ' ');
11612685Sakolb } else {
11622685Sakolb (void) printf("%-*d", width, (int)home);
11632685Sakolb }
11642685Sakolb
11652685Sakolb /*
11662685Sakolb * Print change in affinities from old to new
11672685Sakolb */
11682685Sakolb print_affinities(lgrps_changed, init_affs, NLGRPS);
11692685Sakolb (void) printf(" => ");
11702685Sakolb print_affinities(lgrps_changed, cur_affs, NLGRPS);
11712685Sakolb (void) printf("\n");
11722685Sakolb }
11732685Sakolb
11742685Sakolb free(lgrps_changed);
11752685Sakolb free(init_affs);
11762685Sakolb free(cur_affs);
11772685Sakolb
11782685Sakolb break;
11792685Sakolb
11802685Sakolb default:
11812685Sakolb break;
11822685Sakolb }
11832685Sakolb
11842685Sakolb return (0);
11852685Sakolb }
11862685Sakolb
11872685Sakolb
11882685Sakolb /*
11892685Sakolb * Routine called by Plwp_iter_all() as it iterates through LWPs of another
11902685Sakolb * process
11912685Sakolb */
11922685Sakolb /* ARGSUSED */
11932685Sakolb static int
Plwp_iter_handler(void * arg,const lwpstatus_t * lwpstatus,const lwpsinfo_t * lwpsinfo)11942685Sakolb Plwp_iter_handler(void *arg, const lwpstatus_t *lwpstatus,
11952685Sakolb const lwpsinfo_t *lwpsinfo)
11962685Sakolb {
11972685Sakolb id_t lwpid;
11982685Sakolb struct ps_prochandle *Ph;
11992685Sakolb const pstatus_t *pstatus;
12002685Sakolb plgrp_args_t *plgrp_args;
12012685Sakolb
12022685Sakolb /*
12032685Sakolb * Nothing to do if no arguments
12042685Sakolb */
12052685Sakolb if (arg == NULL || interrupt)
12062685Sakolb return (0);
12072685Sakolb
12082685Sakolb /*
12092685Sakolb * Unpack plgrp(1) arguments and state needed to process this LWP
12102685Sakolb */
12112685Sakolb plgrp_args = arg;
12122685Sakolb Ph = plgrp_args->Ph;
12132685Sakolb
12142685Sakolb /*
12152685Sakolb * Just return if no /proc handle for process
12162685Sakolb */
12172685Sakolb if (Ph == NULL)
12182685Sakolb return (0);
12192685Sakolb
12202685Sakolb pstatus = Pstatus(Ph);
12212685Sakolb
12222685Sakolb /*
12232685Sakolb * Skip agent LWP and any LWPs that weren't specified
12242685Sakolb */
12252685Sakolb lwpid = lwpsinfo->pr_lwpid;
12262685Sakolb if (lwpid == pstatus->pr_agentid ||
12272685Sakolb !proc_lwp_in_set(plgrp_args->lwps, lwpid))
12282685Sakolb return (0);
12292685Sakolb
12302685Sakolb plgrp_args->nthreads++;
12312685Sakolb
12322685Sakolb /*
12332685Sakolb * Do all plgrp(1) operations specified on given thread
12342685Sakolb */
12352685Sakolb (void) printf(FMT_THREAD" ", (int)pstatus->pr_pid, (int)lwpid);
12362685Sakolb return (do_op(plgrp_args, pstatus->pr_pid, lwpid, lwpsinfo));
12372685Sakolb }
12382685Sakolb
12392685Sakolb /*
12402685Sakolb * Get target process specified in "pidstring" argument to do operation(s)
12412685Sakolb * specified in "plgrp_todo" using /proc and agent LWP
12422685Sakolb */
12432685Sakolb static void
do_process(char * pidstring,plgrp_args_t * plgrp_todo,int force)12442685Sakolb do_process(char *pidstring, plgrp_args_t *plgrp_todo, int force)
12452685Sakolb {
12462685Sakolb int error;
12472685Sakolb const char *lwps;
12482685Sakolb struct ps_prochandle *Ph;
12492685Sakolb
12502685Sakolb /*
12512685Sakolb * Nothing to do, so return.
12522685Sakolb */
12532685Sakolb if (plgrp_todo == NULL || interrupt)
12542685Sakolb return;
12552685Sakolb
12562685Sakolb /*
12572685Sakolb * Grab target process or core and return
12582685Sakolb * /proc handle for process and string of LWP
12592685Sakolb * IDs
12602685Sakolb */
12612685Sakolb Ph = proc_arg_xgrab(pidstring, NULL,
12622685Sakolb PR_ARG_ANY, force | PGRAB_RETAIN | PGRAB_NOSTOP, &error, &lwps);
12632685Sakolb if (Ph == NULL) {
12642685Sakolb (void) fprintf(stderr,
12652685Sakolb gettext("%s: Unable to grab process %s: %s\n"),
12662685Sakolb progname, pidstring, Pgrab_error(error));
12672685Sakolb nerrors++;
12682685Sakolb return;
12692685Sakolb }
12702685Sakolb
12712685Sakolb /*
12722685Sakolb * Fill in remaining plgrp(1) arguments and state needed to do
12732685Sakolb * plgrp(1) operation(s) on desired LWPs in our handler
12742685Sakolb * called by Plwp_iter_all() as it iterates over LWPs
12752685Sakolb * in given process
12762685Sakolb */
12772685Sakolb plgrp_todo->Ph = Ph;
12782685Sakolb plgrp_todo->lwps = lwps;
12792685Sakolb
12802685Sakolb /*
12812685Sakolb * Iterate over LWPs in process and do specified
12822685Sakolb * operation(s) on those specified
12832685Sakolb */
12842685Sakolb if (Plwp_iter_all(Ph, Plwp_iter_handler, plgrp_todo) != 0) {
12852685Sakolb (void) fprintf(stderr,
12862685Sakolb gettext("%s: error iterating over threads\n"),
12872685Sakolb progname);
12882685Sakolb nerrors++;
12892685Sakolb }
12902685Sakolb
12912685Sakolb Prelease(Ph, PRELEASE_RETAIN);
12922685Sakolb }
12932685Sakolb
12942685Sakolb
12952685Sakolb /*
12962685Sakolb * Parse command line and kick off any resulting actions
12972685Sakolb *
12982685Sakolb * plgrp(1) has the following command line syntax:
12992685Sakolb *
13002685Sakolb * plgrp [-h] <pid> | <core> [/lwps] ...
13012685Sakolb * plgrp [-F] -a <lgroup>,... <pid>[/lwps] ...
13022685Sakolb * plgrp [-F] -H <lgroup>,... <pid>[/lwps] ...
13032685Sakolb * plgrp [-F] -A <lgroup>,... [/none|weak|strong] ... <pid>[/lwps] ...
13042685Sakolb *
13052685Sakolb * where <lgroup> is an lgroup ID, "all", "root", "leaves".
13062685Sakolb */
13072685Sakolb int
main(int argc,char * argv[])13082685Sakolb main(int argc, char *argv[])
13092685Sakolb {
13102685Sakolb lgrp_affinity_t aff;
13112685Sakolb char *affstring;
13122685Sakolb int c;
13132685Sakolb lgrp_cookie_t cookie;
13142685Sakolb int Fflag;
13152685Sakolb int i;
13162685Sakolb int opt_seen;
13172685Sakolb plgrp_args_t plgrp_todo;
13182685Sakolb char *s;
13192685Sakolb
13202685Sakolb (void) setlocale(LC_ALL, "");
13212685Sakolb (void) textdomain(TEXT_DOMAIN);
13222685Sakolb
13232685Sakolb opt_seen = 0;
13242685Sakolb
13252685Sakolb /*
13262685Sakolb * Get name of program
13272685Sakolb */
13282685Sakolb progname = basename(argv[0]);
13292685Sakolb
13302685Sakolb /*
13312685Sakolb * Not much to do when only name of program given
13322685Sakolb */
13332685Sakolb if (argc == 1)
13342685Sakolb usage(0);
13352685Sakolb
13362685Sakolb /*
13372685Sakolb * Catch signals from terminal, so they can be handled asynchronously
13382685Sakolb * when we're ready instead of when we're not (;-)
13392685Sakolb */
13402685Sakolb if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
13412685Sakolb (void) sigset(SIGHUP, intr);
13422685Sakolb if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
13432685Sakolb (void) sigset(SIGINT, intr);
13442685Sakolb if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
13452685Sakolb (void) sigset(SIGQUIT, intr);
13462685Sakolb (void) sigset(SIGPIPE, intr);
13472685Sakolb (void) sigset(SIGTERM, intr);
13482685Sakolb
13492685Sakolb /*
13502685Sakolb * Take snapshot of lgroup hierarchy
13512685Sakolb */
13522685Sakolb cookie = lgrp_init(LGRP_VIEW_OS);
13532685Sakolb if (cookie == LGRP_COOKIE_NONE) {
13542685Sakolb (void) fprintf(stderr,
13552685Sakolb gettext("%s: Fatal error: cannot get lgroup"
13562685Sakolb " information from the OS: %s\n"),
13572685Sakolb progname, strerror(errno));
13582685Sakolb return (EXIT_FAILURE);
13592685Sakolb }
13602685Sakolb
13612685Sakolb root = lgrp_root(cookie);
13622685Sakolb lgrps_bitmap_init(cookie, root, &lgrps_bitmap, &lgrps_bitmap_nelements);
13632685Sakolb
13642685Sakolb /*
13652685Sakolb * Remember arguments and state needed to do plgrp(1) operation
13662685Sakolb * on desired LWPs
13672685Sakolb */
13682685Sakolb bzero(&plgrp_todo, sizeof (plgrp_args_t));
13692685Sakolb plgrp_todo.op = PLGRP_HOME_GET;
13702685Sakolb
13712685Sakolb /*
13722685Sakolb * Parse options
13732685Sakolb */
13742685Sakolb opterr = 0;
13752685Sakolb Fflag = 0;
13762685Sakolb while (!interrupt && (c = getopt(argc, argv, "a:A:FhH:")) != -1) {
13772685Sakolb /*
13782685Sakolb * Parse option and only allow one option besides -F to be
13792685Sakolb * specified
13802685Sakolb */
13812685Sakolb switch (c) {
13822685Sakolb
13832685Sakolb case 'h': /* Get home lgroup */
13842685Sakolb /*
13852685Sakolb * Only allow one option (besides -F) to be specified
13862685Sakolb */
13872685Sakolb if (opt_seen)
13882685Sakolb usage(EXIT_FAILURE);
13892685Sakolb opt_seen = 1;
13902685Sakolb
13912685Sakolb plgrp_todo.op = PLGRP_HOME_GET;
13922685Sakolb break;
13932685Sakolb
13942685Sakolb case 'H': /* Set home lgroup */
13952685Sakolb
13962685Sakolb /*
13972685Sakolb * Fail if already specified option (besides -F)
13982685Sakolb * or no more arguments
13992685Sakolb */
14002685Sakolb if (opt_seen || optind >= argc) {
14012685Sakolb usage(EXIT_FAILURE);
14022685Sakolb }
14032685Sakolb opt_seen = 1;
14042685Sakolb
14052685Sakolb plgrp_todo.op = PLGRP_HOME_SET;
14062685Sakolb
14072685Sakolb if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0)
14082685Sakolb usage(EXIT_FAILURE);
14092685Sakolb
14102685Sakolb /* If there are no valid lgroups exit immediately */
14112685Sakolb if (plgrp_todo.nlgrps == 0) {
14122685Sakolb (void) fprintf(stderr,
14132685Sakolb gettext("%s: no valid lgroups"
14142685Sakolb " specified for -%c\n\n"),
14152685Sakolb progname, c);
14162685Sakolb usage(EXIT_FAILURE);
14172685Sakolb }
14182685Sakolb
14192685Sakolb break;
14202685Sakolb
14212685Sakolb case 'a': /* Get lgroup affinity */
14222685Sakolb
14232685Sakolb /*
14242685Sakolb * Fail if already specified option (besides -F)
14252685Sakolb * or no more arguments
14262685Sakolb */
14272685Sakolb if (opt_seen || optind >= argc) {
14282685Sakolb usage(EXIT_FAILURE);
14292685Sakolb }
14302685Sakolb opt_seen = 1;
14312685Sakolb
14322685Sakolb plgrp_todo.op = PLGRP_AFFINITY_GET;
14332685Sakolb
14342685Sakolb if (parse_lgrps(cookie, &plgrp_todo, optarg) < 0)
14352685Sakolb usage(EXIT_FAILURE);
14362685Sakolb
14372685Sakolb /* If there are no valid lgroups exit immediately */
14382685Sakolb if (plgrp_todo.nlgrps == 0) {
14392685Sakolb (void) fprintf(stderr,
14402685Sakolb gettext("%s: no valid lgroups specified"
14412685Sakolb " for -%c\n\n"),
14422685Sakolb progname, c);
14432685Sakolb usage(EXIT_FAILURE);
14442685Sakolb }
14452685Sakolb
14462685Sakolb break;
14472685Sakolb
14482685Sakolb case 'A': /* Set lgroup affinity */
14492685Sakolb
14502685Sakolb /*
14512685Sakolb * Fail if already specified option (besides -F)
14522685Sakolb * or no more arguments
14532685Sakolb */
14542685Sakolb if (opt_seen || optind >= argc) {
14552685Sakolb usage(EXIT_FAILURE);
14562685Sakolb }
14572685Sakolb opt_seen = 1;
14582685Sakolb
14592685Sakolb plgrp_todo.op = PLGRP_AFFINITY_SET;
14602685Sakolb
14612685Sakolb /*
14622685Sakolb * 'affstring' is the unparsed prtion of the affinity
14632685Sakolb * specification like 1,2/none,2/weak,0/strong
14642685Sakolb *
14652685Sakolb * 'next' is the next affinity specification to parse.
14662685Sakolb */
14672685Sakolb affstring = optarg;
14682685Sakolb while (affstring != NULL && strlen(affstring) > 0) {
14692685Sakolb char *next;
14702685Sakolb
14712685Sakolb /*
14722685Sakolb * affstring points to the first affinity
14732685Sakolb * specification. Split the string by
14742685Sakolb * DELIMIT_AFF separator and parse lgroups and
14752685Sakolb * affinity value separately.
14762685Sakolb */
14772685Sakolb s = strchr(affstring, DELIMIT_AFF);
14782685Sakolb if (s == NULL) {
14792685Sakolb (void) fprintf(stderr,
14802685Sakolb gettext("%s: invalid "
14812685Sakolb "syntax >%s<\n"),
14822685Sakolb progname, affstring);
14832685Sakolb usage(EXIT_FAILURE);
14842685Sakolb }
14852685Sakolb
14862685Sakolb aff = parse_lgrp_affinity(s, &next);
14872685Sakolb if (aff == LGRP_AFF_INVALID) {
14882685Sakolb (void) fprintf(stderr,
14892685Sakolb gettext("%s: invalid "
14902685Sakolb "affinity >%s<\n"),
14912685Sakolb progname, affstring);
14922685Sakolb usage(EXIT_FAILURE);
14932685Sakolb }
14942685Sakolb
14952685Sakolb /*
14962685Sakolb * next should either point to the empty string
14972685Sakolb * or to the DELIMIT_AFF_LST separator.
14982685Sakolb */
14992685Sakolb if (*next != '\0') {
15002685Sakolb if (*next != DELIMIT_AFF_LST) {
15012685Sakolb (void) fprintf(stderr,
15022685Sakolb gettext("%s: invalid "
15032685Sakolb "syntax >%s<\n"),
15042685Sakolb progname, next);
15052685Sakolb usage(EXIT_FAILURE);
15062685Sakolb }
15072685Sakolb *next = '\0';
15082685Sakolb next++;
15092685Sakolb }
15102685Sakolb
15112685Sakolb
15122685Sakolb /*
15132685Sakolb * Now parse the list of lgroups
15142685Sakolb */
15152685Sakolb if (parse_lgrps(cookie, &plgrp_todo,
15162685Sakolb affstring) < 0) {
15172685Sakolb usage(EXIT_FAILURE);
15182685Sakolb }
15192685Sakolb
15202685Sakolb /*
15212685Sakolb * Set desired affinity for specified lgroup to
15222685Sakolb * the specified affinity.
15232685Sakolb */
15242685Sakolb for (i = 0; i < plgrp_todo.nlgrps; i++) {
15252685Sakolb if (plgrp_todo.affs[i] ==
15262685Sakolb LGRP_AFF_INVALID)
15272685Sakolb plgrp_todo.affs[i] = aff;
15282685Sakolb }
15292685Sakolb
15302685Sakolb /*
15312685Sakolb * We processed the leftmost element of the
15322685Sakolb * list. Advance affstr to the remaining part of
15332685Sakolb * the list. and repeat.
15342685Sakolb */
15352685Sakolb affstring = next;
15362685Sakolb }
15372685Sakolb
15382685Sakolb /*
15392685Sakolb * If there are no valid lgroups, exit immediately
15402685Sakolb */
15412685Sakolb if (plgrp_todo.nlgrps == 0) {
15422685Sakolb (void) fprintf(stderr,
15432685Sakolb gettext("%s: no valid lgroups specified "
15442685Sakolb "for -%c\n\n"), progname, c);
15452685Sakolb usage(EXIT_FAILURE);
15462685Sakolb }
15472685Sakolb
15482685Sakolb break;
15492685Sakolb
15502685Sakolb case 'F': /* Force */
15512685Sakolb
15522685Sakolb /*
15532685Sakolb * Only allow one occurrence
15542685Sakolb */
15552685Sakolb if (Fflag != 0) {
15562685Sakolb usage(EXIT_FAILURE);
15572685Sakolb }
15582685Sakolb
15592685Sakolb /*
15602685Sakolb * Set flag to force /proc to grab process even though
15612685Sakolb * it's been grabbed by another process already
15622685Sakolb */
15632685Sakolb Fflag = PGRAB_FORCE;
15642685Sakolb break;
15652685Sakolb
15662685Sakolb case '?': /* Unrecognized option */
15672685Sakolb default:
15682685Sakolb usage(EXIT_FAILURE);
15692685Sakolb break;
15702685Sakolb
15712685Sakolb }
15722685Sakolb }
15732685Sakolb
15742685Sakolb /*
15752685Sakolb * Should have more arguments left at least for PID or core
15762685Sakolb */
15772685Sakolb if (optind >= argc)
15782685Sakolb usage(EXIT_FAILURE);
15792685Sakolb
15802685Sakolb (void) lgrp_fini(cookie);
15812685Sakolb
15822685Sakolb /*
15832685Sakolb * Print heading and process each [pid | core]/lwps argument
15842685Sakolb */
15852685Sakolb print_heading(plgrp_todo.op);
1586*7032Sakolb (void) proc_initstdio();
1587*7032Sakolb
15882685Sakolb for (i = optind; i < argc && !interrupt; i++) {
1589*7032Sakolb (void) proc_flushstdio();
15902685Sakolb do_process(argv[i], &plgrp_todo, Fflag);
15912685Sakolb }
15922685Sakolb
1593*7032Sakolb (void) proc_finistdio();
1594*7032Sakolb
15952685Sakolb if (plgrp_todo.nthreads == 0) {
15962685Sakolb (void) fprintf(stderr, gettext("%s: no matching LWPs found\n"),
15972685Sakolb progname);
15982685Sakolb }
15992685Sakolb
16002685Sakolb return ((nerrors ||interrupt) ? EXIT_NONFATAL : EXIT_SUCCESS);
16012685Sakolb }
1602