blob: 708abd9f275ac29c9d5fd30e1eb398683d4c8935 [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);
Denis Vlasenko44f08212008-04-25 17:01:06 +000096 enum { CNT_BIT = CPU_SETSIZE < sizeof(m)*8 ? CPU_SETSIZE : sizeof(m)*8 };
97
Denis Vlasenkob44c7902008-03-17 09:29:43 +000098 CPU_ZERO(&mask);
Denis Vlasenko44f08212008-04-25 17:01:06 +000099 for (i = 0; i < CNT_BIT; i++) {
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000100 unsigned long long bit = (1ULL << i);
101 if (bit & m)
102 CPU_SET(i, &mask);
103 }
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +0000104 }
Denis Vlasenkob44c7902008-03-17 09:29:43 +0000105
106 /* Set pid's or our own (pid==0) affinity */
107 if (sched_setaffinity(pid, sizeof(mask), &mask))
108 bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
109
110 if (!*argv) /* "-p <aff> <pid> [...ignored...]" */
111 goto print_aff; /* print new affinity and exit */
112
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000113 BB_EXECVP(*argv, argv);
Denis Vlasenko0c97c9d2007-10-01 11:58:38 +0000114 bb_simple_perror_msg_and_die(*argv);
Bernhard Reutner-Fischer32eddff2006-11-22 16:39:48 +0000115}