2 * taskset.c - set or retrieve a task's CPU affinity
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2, as
6 * published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 * Copyright (C) 2004 Robert Love
18 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
36 #include "closestream.h"
38 #ifndef PF_NO_SETAFFINITY
39 # define PF_NO_SETAFFINITY 0x04000000
43 pid_t pid
; /* task PID */
44 cpu_set_t
*set
; /* task CPU mask */
46 char *buf
; /* buffer for conversion from mask to string */
48 unsigned int use_list
:1, /* use list rather than masks */
49 get_only
:1; /* print the mask, but not modify */
52 static void __attribute__((__noreturn__
)) usage(void)
56 _("Usage: %s [options] [mask | cpu-list] [pid|cmd [args...]]\n\n"),
57 program_invocation_short_name
);
59 fputs(USAGE_SEPARATOR
, out
);
60 fputs(_("Show or change the CPU affinity of a process.\n"), out
);
61 fputs(USAGE_SEPARATOR
, out
);
65 " -a, --all-tasks operate on all the tasks (threads) for a given pid\n"
66 " -p, --pid operate on existing given pid\n"
67 " -c, --cpu-list display and specify cpus in list format\n"
69 fprintf(out
, USAGE_HELP_OPTIONS(25));
71 fputs(USAGE_SEPARATOR
, out
);
73 "The default behavior is to run a new command:\n"
74 " %1$s 03 sshd -b 1024\n"
75 "You can retrieve the mask of an existing task:\n"
79 "List format uses a comma-separated list instead of a mask:\n"
80 " %1$s -pc 0,3,7-11 700\n"
81 "Ranges in list format can take a stride argument:\n"
82 " e.g. 0-31:2 is equivalent to mask 0x55555555\n"),
83 program_invocation_short_name
);
85 fprintf(out
, USAGE_MAN_TAIL("taskset(1)"));
89 static void print_affinity(struct taskset
*ts
, int isnew
)
94 str
= cpulist_create(ts
->buf
, ts
->buflen
, ts
->set
, ts
->setsize
);
95 msg
= isnew
? _("pid %d's new affinity list: %s\n") :
96 _("pid %d's current affinity list: %s\n");
98 str
= cpumask_create(ts
->buf
, ts
->buflen
, ts
->set
, ts
->setsize
);
99 msg
= isnew
? _("pid %d's new affinity mask: %s\n") :
100 _("pid %d's current affinity mask: %s\n");
104 errx(EXIT_FAILURE
, _("internal error: conversion from cpuset to string failed"));
106 printf(msg
, ts
->pid
? ts
->pid
: getpid(), str
);
109 static void __attribute__((__noreturn__
)) err_affinity(pid_t pid
, int set
)
113 msg
= set
? _("failed to set pid %d's affinity") :
114 _("failed to get pid %d's affinity");
116 err(EXIT_FAILURE
, msg
, pid
? pid
: getpid());
120 static void do_taskset(struct taskset
*ts
, size_t setsize
, cpu_set_t
*set
)
122 /* read the current mask */
124 if (sched_getaffinity(ts
->pid
, ts
->setsize
, ts
->set
) < 0)
125 err_affinity(ts
->pid
, 0);
126 print_affinity(ts
, FALSE
);
133 if (sched_setaffinity(ts
->pid
, setsize
, set
) < 0) {
139 && (pc
= ul_new_procfs_path(ts
->pid
, NULL
))
140 && procfs_process_get_stat_nth(pc
, 9, &flags
) == 0
141 && (flags
& PF_NO_SETAFFINITY
)) {
142 warnx(_("affinity cannot be set due to PF_NO_SETAFFINITY flag set"));
147 err_affinity(ts
->pid
, 1);
150 /* re-read the current mask */
152 if (sched_getaffinity(ts
->pid
, ts
->setsize
, ts
->set
) < 0)
153 err_affinity(ts
->pid
, 0);
154 print_affinity(ts
, TRUE
);
158 int main(int argc
, char **argv
)
162 int c
, all_tasks
= 0;
164 size_t new_setsize
, nbits
;
167 static const struct option longopts
[] = {
168 { "all-tasks", 0, NULL
, 'a' },
169 { "pid", 0, NULL
, 'p' },
170 { "cpu-list", 0, NULL
, 'c' },
171 { "help", 0, NULL
, 'h' },
172 { "version", 0, NULL
, 'V' },
176 setlocale(LC_ALL
, "");
177 bindtextdomain(PACKAGE
, LOCALEDIR
);
179 close_stdout_atexit();
181 memset(&ts
, 0, sizeof(ts
));
183 while ((c
= getopt_long(argc
, argv
, "+apchV", longopts
, NULL
)) != -1) {
189 pid
= strtos32_or_err(argv
[argc
- 1],
190 _("invalid PID argument"));
197 print_version(EXIT_SUCCESS
);
201 errtryhelp(EXIT_FAILURE
);
205 if ((!pid
&& argc
- optind
< 2)
206 || (pid
&& (argc
- optind
< 1 || argc
- optind
> 2))) {
207 warnx(_("bad usage"));
208 errtryhelp(EXIT_FAILURE
);
211 ncpus
= get_max_number_of_cpus();
213 errx(EXIT_FAILURE
, _("cannot determine NR_CPUS; aborting"));
216 * the ts->set is always used for the sched_getaffinity call
217 * On the sched_getaffinity the kernel demands a user mask of
218 * at least the size of its own cpumask_t.
220 ts
.set
= cpuset_alloc(ncpus
, &ts
.setsize
, &nbits
);
222 err(EXIT_FAILURE
, _("cpuset_alloc failed"));
224 /* buffer for conversion from mask to string */
225 ts
.buflen
= 7 * nbits
;
226 ts
.buf
= xmalloc(ts
.buflen
);
229 * new_set is always used for the sched_setaffinity call
230 * On the sched_setaffinity the kernel will zero-fill its
231 * cpumask_t if the user's mask is shorter.
233 new_set
= cpuset_alloc(ncpus
, &new_setsize
, NULL
);
235 err(EXIT_FAILURE
, _("cpuset_alloc failed"));
237 if (argc
- optind
== 1)
240 else if (ts
.use_list
) {
241 if (cpulist_parse(argv
[optind
], new_set
, new_setsize
, 0))
242 errx(EXIT_FAILURE
, _("failed to parse CPU list: %s"),
244 } else if (cpumask_parse(argv
[optind
], new_set
, new_setsize
)) {
245 errx(EXIT_FAILURE
, _("failed to parse CPU mask: %s"),
249 if (all_tasks
&& pid
) {
251 struct path_cxt
*pc
= ul_new_procfs_path(pid
, NULL
);
253 while (pc
&& procfs_process_next_tid(pc
, &sub
, &ts
.pid
) == 0)
254 do_taskset(&ts
, new_setsize
, new_set
);
259 do_taskset(&ts
, new_setsize
, new_set
);
264 cpuset_free(new_set
);
268 execvp(argv
[0], argv
);