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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * psrset - create and manage processor sets
30 #include <sys/types.h>
31 #include <sys/procset.h>
32 #include <sys/processor.h>
45 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
46 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
49 #define MAX_PROCFS_PATH 80
51 #define ERR_OK 0 /* exit status for success */
52 #define ERR_FAIL 1 /* exit status for errors */
53 #define ERR_USAGE 2 /* exit status for usage errors */
55 static char *progname
;
73 extern int pset_assign_forced(psetid_t
, processorid_t
, psetid_t
*);
77 warn(char *format
, ...)
82 (void) fprintf(stderr
, "%s: ", progname
);
83 va_start(alist
, format
);
84 (void) vfprintf(stderr
, format
, alist
);
86 if (strchr(format
, '\n') == NULL
)
87 (void) fprintf(stderr
, ": %s\n", strerror(err
));
92 die(char *format
, ...)
97 (void) fprintf(stderr
, "%s: ", progname
);
98 va_start(alist
, format
);
99 (void) vfprintf(stderr
, format
, alist
);
101 if (strchr(format
, '\n') == NULL
)
102 (void) fprintf(stderr
, ": %s\n", strerror(err
));
106 static struct ps_prochandle
*
110 struct ps_prochandle
*Pr
;
112 if ((Pr
= Pgrab(pid
, 0, &ret
)) == NULL
) {
113 warn(gettext("cannot control process %d: %s\n"),
114 (int)pid
, Pgrab_error(ret
));
123 rele_proc(struct ps_prochandle
*Pr
)
131 bind_err(psetid_t pset
, id_t pid
, id_t lwpid
, int err
)
137 msg
= gettext("unbind");
140 msg
= gettext("query");
143 msg
= gettext("bind");
149 warn(gettext("cannot %s pid %d"), msg
, pid
);
151 warn(gettext("cannot %s lwpid %d/%d"), msg
, pid
, lwpid
);
158 create_out(psetid_t pset
)
160 (void) printf("%s %d\n", gettext("created processor set"), pset
);
167 assign_out(processorid_t cpu
, psetid_t old
, psetid_t
new)
169 if (old
== PS_NONE
) {
171 (void) printf(gettext("processor %d: was not assigned,"
172 " now not assigned\n"), cpu
);
174 (void) printf(gettext("processor %d: was not assigned,"
175 " now %d\n"), cpu
, new);
178 (void) printf(gettext("processor %d: was %d, "
179 "now not assigned\n"), cpu
, old
);
181 (void) printf(gettext("processor %d: was %d, "
182 "now %d\n"), cpu
, old
, new);
190 query_out(id_t pid
, id_t lwpid
, psetid_t pset
)
196 (void) snprintf(pidstr
, 20, "%d", pid
);
199 (void) snprintf(pidstr
, 20, "%d/%d", pid
, lwpid
);
204 (void) printf(gettext("%s id %s: not bound\n"),
207 (void) printf(gettext("%s id %s: %d\n"), proclwp
, pidstr
, pset
);
214 info_out(psetid_t pset
, int type
, uint_t numcpus
, processorid_t
*cpus
)
217 if (type
== PS_SYSTEM
)
218 (void) printf(gettext("system processor set %d:"), pset
);
220 (void) printf(gettext("user processor set %d:"), pset
);
222 (void) printf(gettext(" empty"));
223 else if (numcpus
> 1)
224 (void) printf(gettext(" processors"));
226 (void) printf(gettext(" processor"));
227 for (i
= 0; i
< numcpus
; i
++)
228 (void) printf(" %d", cpus
[i
]);
236 print_out(processorid_t cpu
, psetid_t pset
)
239 (void) printf(gettext("processor %d: not assigned\n"), cpu
);
241 (void) printf(gettext("processor %d: %d\n"), cpu
, pset
);
248 bind_out(id_t pid
, id_t lwpid
, psetid_t old
, psetid_t
new)
254 (void) snprintf(pidstr
, 20, "%d", pid
);
257 (void) snprintf(pidstr
, 20, "%d/%d", pid
, lwpid
);
261 if (old
== PS_NONE
) {
263 (void) printf(gettext("%s id %s: was not bound, "
264 "now not bound\n"), proclwp
, pidstr
);
266 (void) printf(gettext("%s id %s: was not bound, "
267 "now %d\n"), proclwp
, pidstr
, new);
270 (void) printf(gettext("%s id %s: was %d, "
271 "now not bound\n"), proclwp
, pidstr
, old
);
273 (void) printf(gettext("%s id %s: was %d, "
274 "now %d\n"), proclwp
, pidstr
, old
, new);
279 bind_lwp(id_t pid
, id_t lwpid
, psetid_t pset
)
283 if (pset_bind_lwp(pset
, lwpid
, pid
, &old_pset
) != 0) {
284 bind_err(pset
, pid
, lwpid
, errno
);
287 if (errors
!= ERR_FAIL
) {
289 query_out(pid
, lwpid
, old_pset
);
291 bind_out(pid
, lwpid
, old_pset
, pset
);
296 do_cpu(psetid_t pset
, processorid_t cpu
, int print
, int mustexist
)
301 if ((!Fflag
&& pset_assign(pset
, cpu
, &old_pset
) != 0) ||
302 (Fflag
&& pset_assign_forced(pset
, cpu
, &old_pset
) != 0)) {
303 if (errno
== EINVAL
&& !mustexist
)
309 warn(gettext("cannot remove processor %d"), cpu
);
312 warn(gettext("cannot query processor %d"), cpu
);
315 warn(gettext("cannot assign processor %d"), cpu
);
321 print_out(cpu
, old_pset
);
323 assign_out(cpu
, old_pset
, pset
);
328 do_range(psetid_t pset
, processorid_t first
, processorid_t last
, int print
)
335 for (cpu
= first
; cpu
<= last
; cpu
++) {
336 if ((err
= do_cpu(pset
, cpu
, print
, 0)) == 0)
338 else if (err
!= EINVAL
)
341 if (!found_one
&& error
== ERR_OK
) {
342 warn(gettext("no processors in range %d-%d\n"), first
, last
);
349 do_info(psetid_t pset
)
355 numcpus
= (uint_t
)sysconf(_SC_NPROCESSORS_MAX
);
356 cpus
= (processorid_t
*)
357 malloc(numcpus
* sizeof (processorid_t
));
359 warn(gettext("memory allocation failed"));
362 if (pset_info(pset
, &type
, &numcpus
, cpus
) != 0) {
363 warn(gettext("cannot get info for processor set %d"), pset
);
367 info_out(pset
, type
, numcpus
, cpus
);
373 do_destroy(psetid_t pset
)
375 if (pset_destroy(pset
) != 0) {
376 warn(gettext("could not remove processor set %d"), pset
);
379 (void) printf(gettext("removed processor set %d\n"), pset
);
384 do_intr(psetid_t pset
, int flag
)
390 numcpus
= (uint_t
)sysconf(_SC_NPROCESSORS_MAX
);
391 cpus
= (processorid_t
*)
392 malloc(numcpus
* sizeof (processorid_t
));
394 warn(gettext("memory allocation failed"));
397 if (pset_info(pset
, NULL
, &numcpus
, cpus
) != 0) {
399 "cannot set interrupt status for processor set %d"), pset
);
403 for (i
= 0; i
< numcpus
; i
++) {
404 int status
= p_online(cpus
[i
], P_STATUS
);
405 if (status
!= P_OFFLINE
&& status
!= P_POWEROFF
&&
407 if (p_online(cpus
[i
], flag
) == -1) {
408 warn(gettext("processor %d"), cpus
[i
]);
418 * Query the type and CPUs for all active processor sets in the system.
424 uint_t npsets
, oldnpsets
;
428 if (pset_list(NULL
, &npsets
) != 0) {
429 warn(gettext("cannot get number of processor sets"));
433 psetlist
= malloc(sizeof (psetid_t
) * npsets
);
434 if (psetlist
== NULL
) {
435 warn(gettext("memory allocation failed"));
439 if (pset_list(psetlist
, &npsets
) != 0) {
440 warn(gettext("cannot get list of processor sets"));
444 if (npsets
<= oldnpsets
)
449 for (i
= 0; i
< npsets
; i
++) {
450 if (do_info(psetlist
[i
]))
458 * Query the processor set assignments for all CPUs in the system.
464 processorid_t cpuid
, max_cpuid
;
467 max_cpuid
= (processorid_t
)sysconf(_SC_CPUID_MAX
);
468 for (cpuid
= 0; cpuid
<= max_cpuid
; cpuid
++) {
469 if (pset_assign(PS_QUERY
, cpuid
, &pset
) == 0) {
471 print_out(cpuid
, pset
);
472 } else if (errno
!= EINVAL
) {
473 warn(gettext("cannot query processor %d"), cpuid
);
482 query_all_proc(psinfo_t
*psinfo
, lwpsinfo_t
*lwpsinfo
, void *arg
)
484 id_t pid
= psinfo
->pr_pid
;
487 if (pset_bind(PS_QUERY
, P_PID
, pid
, &binding
) < 0) {
489 * Ignore search errors. The process may have exited
490 * since we read the directory.
494 bind_err(PS_QUERY
, pid
, -1, errno
);
498 if (binding
!= PS_NONE
)
499 query_out(pid
, -1, binding
);
504 query_all_lwp(psinfo_t
*psinfo
, lwpsinfo_t
*lwpsinfo
, void *arg
)
506 id_t pid
= psinfo
->pr_pid
;
507 id_t lwpid
= lwpsinfo
->pr_lwpid
;
508 psetid_t
*cpuid
= arg
;
509 psetid_t binding
= lwpsinfo
->pr_bindpset
;
511 if (psinfo
->pr_nlwp
== 1)
512 lwpid
= -1; /* report process bindings if only 1 lwp */
513 if ((cpuid
!= NULL
&& *cpuid
== binding
) ||
514 (cpuid
== NULL
&& binding
!= PBIND_NONE
))
515 query_out(pid
, lwpid
, binding
);
520 exec_cmd(psetid_t pset
, char **argv
)
522 if (pset_bind(pset
, P_PID
, P_MYID
, NULL
) != 0) {
523 warn(gettext("cannot exec in processor set %d"), pset
);
527 (void) execvp(argv
[0], argv
);
528 warn(gettext("cannot exec command %s"), argv
[0]);
534 (void) fprintf(stderr
, gettext(
536 "\t%1$s -c [-F] [processor_id ...]\n"
537 "\t%1$s -d processor_set_id ...\n"
538 "\t%1$s -n processor_set_id\n"
539 "\t%1$s -f processor_set_id\n"
540 "\t%1$s -e processor_set_id command [argument(s)...]\n"
541 "\t%1$s -a [-F] processor_set_id processor_id ...\n"
542 "\t%1$s -r [-F] processor_id ...\n"
543 "\t%1$s -p [processorid ...]\n"
544 "\t%1$s -b processor_set_id pid[/lwpids] ...\n"
545 "\t%1$s -u pid[/lwpids] ...\n"
546 "\t%1$s -q [pid[/lwpids] ...]\n"
547 "\t%1$s -U [processor_set_id] ...\n"
548 "\t%1$s -Q [processor_set_id] ...\n"
549 "\t%1$s [-i] [processor_set_id ...]\n"),
555 * Query, set, or clear bindings for the range of LWPs in the given process.
558 do_lwps(id_t pid
, const char *range
, psetid_t pset
)
560 char procfile
[MAX_PROCFS_PATH
];
561 struct ps_prochandle
*Pr
;
562 struct prheader header
;
563 struct lwpsinfo
*lwp
;
570 * Report bindings for LWPs in process 'pid'.
572 (void) snprintf(procfile
, MAX_PROCFS_PATH
,
573 "/proc/%d/lpsinfo", (int)pid
);
574 if ((fd
= open(procfile
, O_RDONLY
)) < 0) {
577 bind_err(pset
, pid
, -1, errno
);
580 if (pread(fd
, &header
, sizeof (header
), 0) != sizeof (header
)) {
582 bind_err(pset
, pid
, -1, errno
);
585 nent
= header
.pr_nent
;
586 size
= header
.pr_entsize
* nent
;
587 ptr
= lpsinfo
= malloc(size
);
588 if (lpsinfo
== NULL
) {
589 bind_err(pset
, pid
, -1, errno
);
592 if (pread(fd
, lpsinfo
, size
, sizeof (header
)) != size
) {
593 bind_err(pset
, pid
, -1, errno
);
599 if ((bflag
|| uflag
) && (Pr
= grab_proc(pid
)) == NULL
) {
605 for (i
= 0; i
< nent
; i
++, ptr
+= header
.pr_entsize
) {
607 lwp
= (lwpsinfo_t
*)ptr
;
608 binding
= lwp
->pr_bindpset
;
609 if (!proc_lwp_in_set(range
, lwp
->pr_lwpid
))
613 bind_lwp(pid
, lwp
->pr_lwpid
, pset
);
614 else if (binding
!= PBIND_NONE
)
615 query_out(pid
, lwp
->pr_lwpid
, binding
);
622 warn(gettext("cannot %s lwpid %d/%s: "
623 "No matching LWPs found\n"),
624 bflag
? "bind" : "query", pid
, range
);
631 main(int argc
, char *argv
[])
637 psetid_t pset
, old_pset
;
640 progname
= argv
[0]; /* put actual command name in messages */
642 (void) setlocale(LC_ALL
, ""); /* setup localization */
643 (void) textdomain(TEXT_DOMAIN
);
645 while ((c
= getopt(argc
, argv
, "cdFarpibqQuUnfe")) != EOF
) {
702 * Make sure that at most one of the options was specified.
704 c
= cflag
+ dflag
+ aflag
+ rflag
+ pflag
+
705 iflag
+ bflag
+ uflag
+ Uflag
+
706 qflag
+ Qflag
+ fflag
+ nflag
+ eflag
;
707 if (c
< 1) { /* nothing specified */
708 iflag
= 1; /* default is to get info */
710 warn(gettext("options are mutually exclusive\n"));
714 if (Fflag
&& (cflag
+ aflag
+ rflag
== 0))
723 * Handle single option cases.
726 (void) proc_walk(query_all_proc
, NULL
, PR_WALK_PROC
);
730 (void) proc_walk(query_all_lwp
, NULL
, PR_WALK_LWP
);
734 if (pset_bind(PS_NONE
, P_ALL
, 0, &old_pset
) != 0)
735 die(gettext("failed to unbind all LWPs"));
738 return (print_all());
744 * Get processor set id.
746 if (aflag
|| bflag
|| fflag
|| nflag
|| eflag
) {
748 /* must specify processor set */
749 warn(gettext("must specify processor set\n"));
752 pset
= strtol(*argv
, &errptr
, 10);
753 if (errptr
!= NULL
&& *errptr
!= '\0' || pset
< 0) {
754 warn(gettext("invalid processor set ID %s\n"), *argv
);
762 if (pset_create(&pset
) != 0) {
763 warn(gettext("could not create processor set"));
770 } else if (iflag
|| dflag
) {
772 warn(gettext("must specify at least one "
777 * Go through listed processor sets.
779 for (; argc
> 0; argv
++, argc
--) {
780 pset
= (psetid_t
)strtol(*argv
, &errptr
, 10);
781 if (errptr
!= NULL
&& *errptr
!= '\0') {
782 warn(gettext("invalid processor set ID %s\n"),
788 errors
= do_info(pset
);
790 errors
= do_destroy(pset
);
794 errors
= do_intr(pset
, P_ONLINE
);
796 errors
= do_intr(pset
, P_NOINTR
);
799 warn(gettext("must specify command\n"));
802 exec_cmd(pset
, argv
);
803 /* if returning, must have had an error */
807 if (cflag
|| aflag
|| rflag
|| pflag
) {
809 * Perform function for each processor specified.
812 warn(gettext("must specify at least one processor\n"));
817 * Go through listed processors.
819 for (; argc
> 0; argv
++, argc
--) {
820 if (strchr(*argv
, '-') == NULL
) {
821 /* individual processor id */
822 cpu
= (processorid_t
)strtol(*argv
, &errptr
, 10);
823 if (errptr
!= NULL
&& *errptr
!= '\0') {
824 warn(gettext("invalid processor "
829 if (do_cpu(pset
, cpu
, pflag
, 1))
832 /* range of processors */
833 processorid_t first
, last
;
835 first
= (processorid_t
)
836 strtol(*argv
, &errptr
, 10);
837 if (*errptr
++ != '-') {
839 "invalid processor range %s\n"),
844 last
= (processorid_t
)
845 strtol(errptr
, &errptr
, 10);
846 if ((errptr
!= NULL
&& *errptr
!= '\0') ||
847 last
< first
|| first
< 0) {
849 "invalid processor range %s\n"),
854 if (do_range(pset
, first
, last
, pflag
))
858 } else if (bflag
|| uflag
|| qflag
) {
860 * Perform function for each pid/lwpid specified.
863 warn(gettext("must specify at least one pid\n"));
868 * Go through listed processes/lwp_ranges.
870 for (; argc
> 0; argv
++, argc
--) {
871 pid
= (id_t
)strtol(*argv
, &errptr
, 10);
873 (errptr
!= NULL
&& *errptr
!= '\0' &&
875 warn(gettext("invalid process ID: %s\n"),
879 if (errptr
!= NULL
&& *errptr
== '/') {
882 * Handle lwp range case
884 const char *lwps
= (const char *)(++errptr
);
886 proc_lwp_range_valid(lwps
) != 0) {
887 warn(gettext("invalid lwp range "
888 "for pid %d\n"), (int)pid
);
893 (void) proc_initstdio();
894 ret
= do_lwps(pid
, lwps
, pset
);
896 (void) proc_finistdio();
901 * Handle whole process case.
903 if (pset_bind(pset
, P_PID
, pid
,
905 bind_err(pset
, pid
, -1, errno
);
910 query_out(pid
, -1, old_pset
);
912 bind_out(pid
, -1, old_pset
, pset
);
917 if (Qflag
|| Uflag
) {
919 * Go through listed processor set IDs.
921 for (; argc
> 0; argv
++, argc
--) {
923 pset
= (id_t
)strtol(*argv
, &errptr
, 10);
925 (errptr
!= NULL
&& *errptr
!= '\0')) {
926 warn(gettext("invalid processor set ID\n"));
930 (void) proc_walk(query_all_lwp
,
935 if (pset_bind(PS_NONE
, P_PSETID
, pset
,
937 warn(gettext("failed to unbind from "
938 "processor set %d"), (int)pset
);