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