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