xref: /onnv-gate/usr/src/cmd/ptools/plgrp/plgrp.c (revision 7032:f2e60d02d9a9)
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