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>
34 #include "procutils.h"
36 #include "closestream.h"
39 pid_t pid
; /* task PID */
40 cpu_set_t
*set
; /* task CPU mask */
42 char *buf
; /* buffer for conversion from mask to string */
44 unsigned int use_list
:1, /* use list rather than masks */
45 get_only
:1; /* print the mask, but not modify */
48 static void __attribute__((__noreturn__
)) usage(void)
52 _("Usage: %s [options] [mask | cpu-list] [pid|cmd [args...]]\n\n"),
53 program_invocation_short_name
);
55 fputs(USAGE_SEPARATOR
, out
);
56 fputs(_("Show or change the CPU affinity of a process.\n"), out
);
57 fputs(USAGE_SEPARATOR
, out
);
61 " -a, --all-tasks operate on all the tasks (threads) for a given pid\n"
62 " -p, --pid operate on existing given pid\n"
63 " -c, --cpu-list display and specify cpus in list format\n"
65 printf(USAGE_HELP_OPTIONS(25));
67 fputs(USAGE_SEPARATOR
, out
);
69 "The default behavior is to run a new command:\n"
70 " %1$s 03 sshd -b 1024\n"
71 "You can retrieve the mask of an existing task:\n"
75 "List format uses a comma-separated list instead of a mask:\n"
76 " %1$s -pc 0,3,7-11 700\n"
77 "Ranges in list format can take a stride argument:\n"
78 " e.g. 0-31:2 is equivalent to mask 0x55555555\n"),
79 program_invocation_short_name
);
81 printf(USAGE_MAN_TAIL("taskset(1)"));
85 static void print_affinity(struct taskset
*ts
, int isnew
)
90 str
= cpulist_create(ts
->buf
, ts
->buflen
, ts
->set
, ts
->setsize
);
91 msg
= isnew
? _("pid %d's new affinity list: %s\n") :
92 _("pid %d's current affinity list: %s\n");
94 str
= cpumask_create(ts
->buf
, ts
->buflen
, ts
->set
, ts
->setsize
);
95 msg
= isnew
? _("pid %d's new affinity mask: %s\n") :
96 _("pid %d's current affinity mask: %s\n");
100 errx(EXIT_FAILURE
, _("internal error: conversion from cpuset to string failed"));
102 printf(msg
, ts
->pid
? ts
->pid
: getpid(), str
);
105 static void __attribute__((__noreturn__
)) err_affinity(pid_t pid
, int set
)
109 msg
= set
? _("failed to set pid %d's affinity") :
110 _("failed to get pid %d's affinity");
112 err(EXIT_FAILURE
, msg
, pid
? pid
: getpid());
115 static void do_taskset(struct taskset
*ts
, size_t setsize
, cpu_set_t
*set
)
117 /* read the current mask */
119 if (sched_getaffinity(ts
->pid
, ts
->setsize
, ts
->set
) < 0)
120 err_affinity(ts
->pid
, 1);
121 print_affinity(ts
, FALSE
);
128 if (sched_setaffinity(ts
->pid
, setsize
, set
) < 0)
129 err_affinity(ts
->pid
, 1);
131 /* re-read the current mask */
133 if (sched_getaffinity(ts
->pid
, ts
->setsize
, ts
->set
) < 0)
134 err_affinity(ts
->pid
, 0);
135 print_affinity(ts
, TRUE
);
139 int main(int argc
, char **argv
)
143 int c
, all_tasks
= 0;
145 size_t new_setsize
, nbits
;
148 static const struct option longopts
[] = {
149 { "all-tasks", 0, NULL
, 'a' },
150 { "pid", 0, NULL
, 'p' },
151 { "cpu-list", 0, NULL
, 'c' },
152 { "help", 0, NULL
, 'h' },
153 { "version", 0, NULL
, 'V' },
157 setlocale(LC_ALL
, "");
158 bindtextdomain(PACKAGE
, LOCALEDIR
);
160 close_stdout_atexit();
162 memset(&ts
, 0, sizeof(ts
));
164 while ((c
= getopt_long(argc
, argv
, "+apchV", longopts
, NULL
)) != -1) {
170 pid
= strtos32_or_err(argv
[argc
- 1],
171 _("invalid PID argument"));
178 print_version(EXIT_SUCCESS
);
182 errtryhelp(EXIT_FAILURE
);
186 if ((!pid
&& argc
- optind
< 2)
187 || (pid
&& (argc
- optind
< 1 || argc
- optind
> 2))) {
188 warnx(_("bad usage"));
189 errtryhelp(EXIT_FAILURE
);
192 ncpus
= get_max_number_of_cpus();
194 errx(EXIT_FAILURE
, _("cannot determine NR_CPUS; aborting"));
197 * the ts->set is always used for the sched_getaffinity call
198 * On the sched_getaffinity the kernel demands a user mask of
199 * at least the size of its own cpumask_t.
201 ts
.set
= cpuset_alloc(ncpus
, &ts
.setsize
, &nbits
);
203 err(EXIT_FAILURE
, _("cpuset_alloc failed"));
205 /* buffer for conversion from mask to string */
206 ts
.buflen
= 7 * nbits
;
207 ts
.buf
= xmalloc(ts
.buflen
);
210 * new_set is always used for the sched_setaffinity call
211 * On the sched_setaffinity the kernel will zero-fill its
212 * cpumask_t if the user's mask is shorter.
214 new_set
= cpuset_alloc(ncpus
, &new_setsize
, NULL
);
216 err(EXIT_FAILURE
, _("cpuset_alloc failed"));
218 if (argc
- optind
== 1)
221 else if (ts
.use_list
) {
222 if (cpulist_parse(argv
[optind
], new_set
, new_setsize
, 0))
223 errx(EXIT_FAILURE
, _("failed to parse CPU list: %s"),
225 } else if (cpumask_parse(argv
[optind
], new_set
, new_setsize
)) {
226 errx(EXIT_FAILURE
, _("failed to parse CPU mask: %s"),
230 if (all_tasks
&& pid
) {
231 struct proc_tasks
*tasks
= proc_open_tasks(pid
);
232 while (!proc_next_tid(tasks
, &ts
.pid
))
233 do_taskset(&ts
, new_setsize
, new_set
);
234 proc_close_tasks(tasks
);
237 do_taskset(&ts
, new_setsize
, new_set
);
242 cpuset_free(new_set
);
246 execvp(argv
[0], argv
);