blob: 4815b6a76e274f20d43b19e9b9bcbe7790c94ba2 [file] [log] [blame]
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +00001/* vi: set sw=4 ts=4: */
2/*
3 * taskset - retrieve or set a processes' CPU affinity
4 * Copyright (c) 2006 Bernhard Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */
8
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +00009#include <sched.h>
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000010#include "libbb.h"
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000011
12#if ENABLE_FEATURE_TASKSET_FANCY
13#define TASKSET_PRINTF_MASK "%s"
14#define from_cpuset(x) __from_cpuset(&x)
15/* craft a string from the mask */
Denis Vlasenko3bba5452006-12-30 17:57:03 +000016static char *__from_cpuset(cpu_set_t *mask)
17{
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000018 int i;
19 char *ret = 0, *str = xzalloc(9);
20
21 for (i = CPU_SETSIZE - 4; i >= 0; i -= 4) {
22 char val = 0;
23 int off;
24 for (off = 0; off <= 3; ++off)
25 if (CPU_ISSET(i+off, mask))
26 val |= 1<<off;
27
28 if (!ret && val)
29 ret = str;
30 *str++ = (val-'0'<=9) ? (val+48) : (val+87);
31 }
32 return ret;
33}
34#else
35#define TASKSET_PRINTF_MASK "%x"
Denis Vlasenko3bba5452006-12-30 17:57:03 +000036/* (void*) cast is for battling gcc: */
37/* "dereferencing type-punned pointer will break strict-aliasing rules" */
38#define from_cpuset(mask) (*(unsigned*)(void*)&(mask))
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000039#endif
40
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000041
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000042int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkob44c7902008-03-17 09:29:43 +000043int taskset_main(int argc ATTRIBUTE_UNUSED, char **argv)
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000044{
Denis Vlasenkob44c7902008-03-17 09:29:43 +000045 cpu_set_t mask;
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000046 pid_t pid = 0;
Denis Vlasenkob44c7902008-03-17 09:29:43 +000047 unsigned opt_p;
48 const char *current_new;
49 char *pid_str;
50 char *aff = aff; /* for compiler */
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000051
Denis Vlasenko45ecfc22008-03-22 17:46:16 +000052 /* NB: we mimic util-linux's taskset: -p does not take
53 * an argument, i.e., "-pN" is NOT valid, only "-p N"!
54 * Indeed, util-linux-2.13-pre7 uses:
55 * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
56
Denis Vlasenkob44c7902008-03-17 09:29:43 +000057 opt_complementary = "-1"; /* at least 1 arg */
58 opt_p = getopt32(argv, "+p");
59 argv += optind;
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000060
Denis Vlasenkob44c7902008-03-17 09:29:43 +000061 if (opt_p) {
62 pid_str = *argv++;
63 if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
64 aff = pid_str;
65 pid_str = *argv; /* NB: *argv != NULL in this case */
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000066 }
Denis Vlasenkob44c7902008-03-17 09:29:43 +000067 /* else it was just "-p <pid>", and *argv == NULL */
68 pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
69 } else {
70 aff = *argv++; /* <aff> <cmd...> */
71 if (!*argv)
72 bb_show_usage();
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000073 }
74
Denis Vlasenkob44c7902008-03-17 09:29:43 +000075 current_new = "current\0new";
76 if (opt_p) {
Denis Vlasenko3bba5452006-12-30 17:57:03 +000077 print_aff:
78 if (sched_getaffinity(pid, sizeof(mask), &mask) < 0)
Denis Vlasenkob44c7902008-03-17 09:29:43 +000079 bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000080 printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
Denis Vlasenkob44c7902008-03-17 09:29:43 +000081 pid, current_new, from_cpuset(mask));
82 if (!*argv) {
83 /* Either it was just "-p <pid>",
84 * or it was "-p <aff> <pid>" and we came here
85 * for the second time (see goto below) */
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000086 return EXIT_SUCCESS;
Denis Vlasenkob44c7902008-03-17 09:29:43 +000087 }
88 *argv = NULL;
89 current_new += 8; /* "new" */
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +000090 }
91
Denis Vlasenkob44c7902008-03-17 09:29:43 +000092 { /* Affinity was specified, translate it into cpu_set_t */
93 unsigned i;
94 /* Do not allow zero mask: */
95 unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
96 CPU_ZERO(&mask);
97 for (i = 0; i < CPU_SETSIZE; i++) {
98 unsigned long long bit = (1ULL << i);
99 if (bit & m)
100 CPU_SET(i, &mask);
101 }
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +0000102 }
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000103
104 /* Set pid's or our own (pid==0) affinity */
105 if (sched_setaffinity(pid, sizeof(mask), &mask))
106 bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
107
108 if (!*argv) /* "-p <aff> <pid> [...ignored...]" */
109 goto print_aff; /* print new affinity and exit */
110
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000111 BB_EXECVP(*argv, argv);
Denis Vlasenko0c97c9d2007-10-01 11:58:38 +0000112 bb_simple_perror_msg_and_die(*argv);
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +0000113}