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