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.
26 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
30 * psrset - create and manage processor sets
33 #include <sys/types.h>
34 #include <sys/procset.h>
35 #include <sys/processor.h>
49 #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
50 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
53 #define MAX_PROCFS_PATH 80
55 #define ERR_OK 0 /* exit status for success */
56 #define ERR_FAIL 1 /* exit status for errors */
57 #define ERR_USAGE 2 /* exit status for usage errors */
59 static char *progname
;
77 static const char *zname
;
79 extern int pset_assign_forced(psetid_t
, processorid_t
, psetid_t
*);
83 warn(char *format
, ...)
88 (void) fprintf(stderr
, "%s: ", progname
);
89 va_start(alist
, format
);
90 (void) vfprintf(stderr
, format
, alist
);
92 if (strchr(format
, '\n') == NULL
)
93 (void) fprintf(stderr
, ": %s\n", strerror(err
));
98 die(char *format
, ...)
103 (void) fprintf(stderr
, "%s: ", progname
);
104 va_start(alist
, format
);
105 (void) vfprintf(stderr
, format
, alist
);
107 if (strchr(format
, '\n') == NULL
)
108 (void) fprintf(stderr
, ": %s\n", strerror(err
));
112 static struct ps_prochandle
*
116 struct ps_prochandle
*Pr
;
118 if ((Pr
= Pgrab(pid
, 0, &ret
)) == NULL
) {
119 warn(gettext("cannot control process %d: %s\n"),
120 (int)pid
, Pgrab_error(ret
));
129 rele_proc(struct ps_prochandle
*Pr
)
137 bind_err(psetid_t pset
, const char *zname
, id_t pid
, id_t lwpid
, int err
)
143 msg
= gettext("unbind");
146 msg
= gettext("query");
149 msg
= gettext("bind");
155 warn(gettext("cannot %s zone %s"), msg
, zname
);
156 else if (lwpid
== -1)
157 warn(gettext("cannot %s pid %d"), msg
, pid
);
159 warn(gettext("cannot %s lwpid %d/%d"), msg
, pid
, lwpid
);
166 create_out(psetid_t pset
)
168 (void) printf("%s %d\n", gettext("created processor set"), pset
);
175 assign_out(processorid_t cpu
, psetid_t old
, psetid_t
new)
177 if (old
== PS_NONE
) {
179 (void) printf(gettext("processor %d: was not assigned,"
180 " now not assigned\n"), cpu
);
182 (void) printf(gettext("processor %d: was not assigned,"
183 " now %d\n"), cpu
, new);
186 (void) printf(gettext("processor %d: was %d, "
187 "now not assigned\n"), cpu
, old
);
189 (void) printf(gettext("processor %d: was %d, "
190 "now %d\n"), cpu
, old
, new);
198 query_out(id_t pid
, id_t lwpid
, psetid_t pset
)
204 (void) snprintf(pidstr
, 20, "%d", pid
);
207 (void) snprintf(pidstr
, 20, "%d/%d", pid
, lwpid
);
212 (void) printf(gettext("%s id %s: not bound\n"),
215 (void) printf(gettext("%s id %s: %d\n"), proclwp
, pidstr
, pset
);
222 info_out(psetid_t pset
, int type
, uint_t numcpus
, processorid_t
*cpus
)
225 if (type
== PS_SYSTEM
)
226 (void) printf(gettext("system processor set %d:"), pset
);
228 (void) printf(gettext("user processor set %d:"), pset
);
230 (void) printf(gettext(" empty"));
231 else if (numcpus
> 1)
232 (void) printf(gettext(" processors"));
234 (void) printf(gettext(" processor"));
235 for (i
= 0; i
< numcpus
; i
++)
236 (void) printf(" %d", cpus
[i
]);
244 print_out(processorid_t cpu
, psetid_t pset
)
247 (void) printf(gettext("processor %d: not assigned\n"), cpu
);
249 (void) printf(gettext("processor %d: %d\n"), cpu
, pset
);
256 bind_out(id_t pid
, id_t lwpid
, psetid_t old
, psetid_t
new)
262 (void) snprintf(pidstr
, 20, "%d", pid
);
265 (void) snprintf(pidstr
, 20, "%d/%d", pid
, lwpid
);
269 if (old
== PS_NONE
) {
271 (void) printf(gettext("%s id %s: was not bound, "
272 "now not bound\n"), proclwp
, pidstr
);
274 (void) printf(gettext("%s id %s: was not bound, "
275 "now %d\n"), proclwp
, pidstr
, new);
278 (void) printf(gettext("%s id %s: was %d, "
279 "now not bound\n"), proclwp
, pidstr
, old
);
281 (void) printf(gettext("%s id %s: was %d, "
282 "now %d\n"), proclwp
, pidstr
, old
, new);
287 bind_lwp(id_t pid
, id_t lwpid
, psetid_t pset
)
291 if (pset_bind_lwp(pset
, lwpid
, pid
, &old_pset
) != 0) {
292 bind_err(pset
, NULL
, pid
, lwpid
, errno
);
295 if (errors
!= ERR_FAIL
) {
297 query_out(pid
, lwpid
, old_pset
);
299 bind_out(pid
, lwpid
, old_pset
, pset
);
304 do_cpu(psetid_t pset
, processorid_t cpu
, int print
, int mustexist
)
309 if ((!Fflag
&& pset_assign(pset
, cpu
, &old_pset
) != 0) ||
310 (Fflag
&& pset_assign_forced(pset
, cpu
, &old_pset
) != 0)) {
311 if (errno
== EINVAL
&& !mustexist
)
317 warn(gettext("cannot remove processor %d"), cpu
);
320 warn(gettext("cannot query processor %d"), cpu
);
323 warn(gettext("cannot assign processor %d"), cpu
);
329 print_out(cpu
, old_pset
);
331 assign_out(cpu
, old_pset
, pset
);
336 do_range(psetid_t pset
, processorid_t first
, processorid_t last
, int print
)
343 for (cpu
= first
; cpu
<= last
; cpu
++) {
344 if ((err
= do_cpu(pset
, cpu
, print
, 0)) == 0)
346 else if (err
!= EINVAL
)
349 if (!found_one
&& error
== ERR_OK
) {
350 warn(gettext("no processors in range %d-%d\n"), first
, last
);
357 do_info(psetid_t pset
)
363 numcpus
= (uint_t
)sysconf(_SC_NPROCESSORS_MAX
);
364 cpus
= (processorid_t
*)
365 malloc(numcpus
* sizeof (processorid_t
));
367 warn(gettext("memory allocation failed"));
370 if (pset_info(pset
, &type
, &numcpus
, cpus
) != 0) {
371 warn(gettext("cannot get info for processor set %d"), pset
);
375 info_out(pset
, type
, numcpus
, cpus
);
381 do_destroy(psetid_t pset
)
383 if (pset_destroy(pset
) != 0) {
384 warn(gettext("could not remove processor set %d"), pset
);
387 (void) printf(gettext("removed processor set %d\n"), pset
);
392 do_intr(psetid_t pset
, int flag
)
398 numcpus
= (uint_t
)sysconf(_SC_NPROCESSORS_MAX
);
399 cpus
= (processorid_t
*)
400 malloc(numcpus
* sizeof (processorid_t
));
402 warn(gettext("memory allocation failed"));
405 if (pset_info(pset
, NULL
, &numcpus
, cpus
) != 0) {
407 "cannot set interrupt status for processor set %d"), pset
);
411 for (i
= 0; i
< numcpus
; i
++) {
412 int status
= p_online(cpus
[i
], P_STATUS
);
413 if (status
!= P_OFFLINE
&& status
!= P_POWEROFF
&&
415 if (p_online(cpus
[i
], flag
) == -1) {
416 warn(gettext("processor %d"), cpus
[i
]);
426 * Query the type and CPUs for all active processor sets in the system.
432 uint_t npsets
, oldnpsets
;
436 if (pset_list(NULL
, &npsets
) != 0) {
437 warn(gettext("cannot get number of processor sets"));
441 psetlist
= malloc(sizeof (psetid_t
) * npsets
);
442 if (psetlist
== NULL
) {
443 warn(gettext("memory allocation failed"));
447 if (pset_list(psetlist
, &npsets
) != 0) {
448 warn(gettext("cannot get list of processor sets"));
452 if (npsets
<= oldnpsets
)
457 for (i
= 0; i
< npsets
; i
++) {
458 if (do_info(psetlist
[i
]))
466 * Query the processor set assignments for all CPUs in the system.
472 processorid_t cpuid
, max_cpuid
;
475 max_cpuid
= (processorid_t
)sysconf(_SC_CPUID_MAX
);
476 for (cpuid
= 0; cpuid
<= max_cpuid
; cpuid
++) {
477 if (pset_assign(PS_QUERY
, cpuid
, &pset
) == 0) {
479 print_out(cpuid
, pset
);
480 } else if (errno
!= EINVAL
) {
481 warn(gettext("cannot query processor %d"), cpuid
);
490 query_all_proc(psinfo_t
*psinfo
, lwpsinfo_t
*lwpsinfo
, void *arg
)
492 id_t pid
= psinfo
->pr_pid
;
495 if (pset_bind(PS_QUERY
, P_PID
, pid
, &binding
) < 0) {
497 * Ignore search errors. The process may have exited
498 * since we read the directory.
502 bind_err(PS_QUERY
, NULL
, pid
, -1, errno
);
506 if (binding
!= PS_NONE
)
507 query_out(pid
, -1, binding
);
512 query_all_lwp(psinfo_t
*psinfo
, lwpsinfo_t
*lwpsinfo
, void *arg
)
514 id_t pid
= psinfo
->pr_pid
;
515 id_t lwpid
= lwpsinfo
->pr_lwpid
;
516 psetid_t
*cpuid
= arg
;
517 psetid_t binding
= lwpsinfo
->pr_bindpset
;
519 if (psinfo
->pr_nlwp
== 1)
520 lwpid
= -1; /* report process bindings if only 1 lwp */
521 if ((cpuid
!= NULL
&& *cpuid
== binding
) ||
522 (cpuid
== NULL
&& binding
!= PBIND_NONE
))
523 query_out(pid
, lwpid
, binding
);
528 exec_cmd(psetid_t pset
, char **argv
)
530 if (pset_bind(pset
, P_PID
, P_MYID
, NULL
) != 0) {
531 warn(gettext("cannot exec in processor set %d"), pset
);
535 (void) execvp(argv
[0], argv
);
536 warn(gettext("cannot exec command %s"), argv
[0]);
542 (void) fprintf(stderr
, gettext(
544 "\t%1$s -c [-F] [processor_id ...]\n"
545 "\t%1$s -d processor_set_id ...\n"
546 "\t%1$s -n processor_set_id\n"
547 "\t%1$s -f processor_set_id\n"
548 "\t%1$s -e processor_set_id command [argument(s)...]\n"
549 "\t%1$s -a [-F] processor_set_id processor_id ...\n"
550 "\t%1$s -r [-F] processor_id ...\n"
551 "\t%1$s -p [processorid ...]\n"
552 "\t%1$s -b processor_set_id pid[/lwpids] ...\n"
553 "\t%1$s -b -z zonename processor_set_id\n"
554 "\t%1$s -u pid[/lwpids] ...\n"
555 "\t%1$s -q [pid[/lwpids] ...]\n"
556 "\t%1$s -U [processor_set_id] ...\n"
557 "\t%1$s -Q [processor_set_id] ...\n"
558 "\t%1$s [-i] [processor_set_id ...]\n"),
564 * Query, set, or clear bindings for the range of LWPs in the given process.
567 do_lwps(id_t pid
, const char *range
, psetid_t pset
)
569 char procfile
[MAX_PROCFS_PATH
];
570 struct ps_prochandle
*Pr
;
571 struct prheader header
;
572 struct lwpsinfo
*lwp
;
579 * Report bindings for LWPs in process 'pid'.
581 (void) snprintf(procfile
, MAX_PROCFS_PATH
,
582 "/proc/%d/lpsinfo", (int)pid
);
583 if ((fd
= open(procfile
, O_RDONLY
)) < 0) {
586 bind_err(pset
, NULL
, pid
, -1, errno
);
589 if (pread(fd
, &header
, sizeof (header
), 0) != sizeof (header
)) {
591 bind_err(pset
, NULL
, pid
, -1, errno
);
594 nent
= header
.pr_nent
;
595 size
= header
.pr_entsize
* nent
;
596 ptr
= lpsinfo
= malloc(size
);
597 if (lpsinfo
== NULL
) {
598 bind_err(pset
, NULL
, pid
, -1, errno
);
601 if (pread(fd
, lpsinfo
, size
, sizeof (header
)) != size
) {
602 bind_err(pset
, NULL
, pid
, -1, errno
);
608 if ((bflag
|| uflag
) && (Pr
= grab_proc(pid
)) == NULL
) {
614 for (i
= 0; i
< nent
; i
++, ptr
+= header
.pr_entsize
) {
616 lwp
= (lwpsinfo_t
*)ptr
;
617 binding
= lwp
->pr_bindpset
;
618 if (!proc_lwp_in_set(range
, lwp
->pr_lwpid
))
622 bind_lwp(pid
, lwp
->pr_lwpid
, pset
);
623 else if (binding
!= PBIND_NONE
)
624 query_out(pid
, lwp
->pr_lwpid
, binding
);
631 warn(gettext("cannot %s lwpid %d/%s: "
632 "No matching LWPs found\n"),
633 bflag
? "bind" : "query", pid
, range
);
640 main(int argc
, char *argv
[])
646 psetid_t pset
, old_pset
;
650 progname
= argv
[0]; /* put actual command name in messages */
652 (void) setlocale(LC_ALL
, ""); /* setup localization */
653 (void) textdomain(TEXT_DOMAIN
);
655 while ((c
= getopt(argc
, argv
, "cdFarpibqQuUnfez:")) != EOF
) {
708 warn(gettext("-z can only be used after -b\n"));
712 warn(gettext("-z can only be specified "
725 * Make sure that at most one of the options was specified.
727 c
= cflag
+ dflag
+ aflag
+ rflag
+ pflag
+
728 iflag
+ bflag
+ uflag
+ Uflag
+
729 qflag
+ Qflag
+ fflag
+ nflag
+ eflag
;
730 if (c
< 1) { /* nothing specified */
731 iflag
= 1; /* default is to get info */
733 warn(gettext("options are mutually exclusive\n"));
737 if (Fflag
&& (cflag
+ aflag
+ rflag
== 0))
746 * Handle single option cases.
749 (void) proc_walk(query_all_proc
, NULL
, PR_WALK_PROC
);
753 (void) proc_walk(query_all_lwp
, NULL
, PR_WALK_LWP
);
757 if (pset_bind(PS_NONE
, P_ALL
, 0, &old_pset
) != 0)
758 die(gettext("failed to unbind all LWPs"));
761 return (print_all());
767 * Get processor set id.
769 if (aflag
|| bflag
|| fflag
|| nflag
|| eflag
) {
771 /* must specify processor set */
772 warn(gettext("must specify processor set\n"));
775 pset
= strtol(*argv
, &errptr
, 10);
776 if (errptr
!= NULL
&& *errptr
!= '\0' || pset
< 0) {
777 warn(gettext("invalid processor set ID %s\n"), *argv
);
785 if (pset_create(&pset
) != 0) {
786 warn(gettext("could not create processor set"));
793 } else if (iflag
|| dflag
) {
795 warn(gettext("must specify at least one "
800 * Go through listed processor sets.
802 for (; argc
> 0; argv
++, argc
--) {
803 pset
= (psetid_t
)strtol(*argv
, &errptr
, 10);
804 if (errptr
!= NULL
&& *errptr
!= '\0') {
805 warn(gettext("invalid processor set ID %s\n"),
811 errors
= do_info(pset
);
813 errors
= do_destroy(pset
);
817 errors
= do_intr(pset
, P_ONLINE
);
819 errors
= do_intr(pset
, P_NOINTR
);
822 warn(gettext("must specify command\n"));
825 exec_cmd(pset
, argv
);
826 /* if returning, must have had an error */
830 if (cflag
|| aflag
|| rflag
|| pflag
) {
832 * Perform function for each processor specified.
835 warn(gettext("must specify at least one processor\n"));
840 * Go through listed processors.
842 for (; argc
> 0; argv
++, argc
--) {
843 if (strchr(*argv
, '-') == NULL
) {
844 /* individual processor id */
845 cpu
= (processorid_t
)strtol(*argv
, &errptr
, 10);
846 if (errptr
!= NULL
&& *errptr
!= '\0') {
847 warn(gettext("invalid processor "
852 if (do_cpu(pset
, cpu
, pflag
, 1))
855 /* range of processors */
856 processorid_t first
, last
;
858 first
= (processorid_t
)
859 strtol(*argv
, &errptr
, 10);
860 if (*errptr
++ != '-') {
862 "invalid processor range %s\n"),
867 last
= (processorid_t
)
868 strtol(errptr
, &errptr
, 10);
869 if ((errptr
!= NULL
&& *errptr
!= '\0') ||
870 last
< first
|| first
< 0) {
872 "invalid processor range %s\n"),
877 if (do_range(pset
, first
, last
, pflag
))
881 } else if (bflag
|| uflag
|| qflag
) {
883 * Perform function for each pid/lwpid specified.
885 if (argc
== 0 && !zflag
) {
886 warn(gettext("must specify at least one pid\n"));
888 } else if (argc
> 0 && zflag
) {
889 warn(gettext("cannot specify extra pids with -z\n"));
894 zid
= getzoneidbyname(zname
);
896 warn(gettext("invalid zone name: %s\n"),
899 } else if (pset_bind(pset
, P_ZONEID
, zid
,
901 bind_err(pset
, zname
, -1, -1, errno
);
904 (void) printf(gettext("zone %s: bound to %d\n"),
910 * Go through listed processes/lwp_ranges.
912 for (; argc
> 0; argv
++, argc
--) {
913 pid
= (id_t
)strtol(*argv
, &errptr
, 10);
915 (errptr
!= NULL
&& *errptr
!= '\0' &&
917 warn(gettext("invalid process ID: %s\n"),
921 if (errptr
!= NULL
&& *errptr
== '/') {
924 * Handle lwp range case
926 const char *lwps
= (const char *)(++errptr
);
928 proc_lwp_range_valid(lwps
) != 0) {
929 warn(gettext("invalid lwp range "
930 "for pid %d\n"), (int)pid
);
935 (void) proc_initstdio();
936 ret
= do_lwps(pid
, lwps
, pset
);
938 (void) proc_finistdio();
943 * Handle whole process case.
945 if (pset_bind(pset
, P_PID
, pid
,
947 bind_err(pset
, NULL
, pid
, -1, errno
);
952 query_out(pid
, -1, old_pset
);
954 bind_out(pid
, -1, old_pset
, pset
);
959 if (Qflag
|| Uflag
) {
961 * Go through listed processor set IDs.
963 for (; argc
> 0; argv
++, argc
--) {
965 pset
= (id_t
)strtol(*argv
, &errptr
, 10);
967 (errptr
!= NULL
&& *errptr
!= '\0')) {
968 warn(gettext("invalid processor set ID\n"));
972 (void) proc_walk(query_all_lwp
,
977 if (pset_bind(PS_NONE
, P_PSETID
, pset
,
979 warn(gettext("failed to unbind from "
980 "processor set %d"), (int)pset
);