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