source: branches/3.2/mindi-busybox/miscutils/taskset.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
  • Property svn:eol-style set to native
File size: 4.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * taskset - retrieve or set a processes' CPU affinity
4 * Copyright (c) 2006 Bernhard Reutner-Fischer
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
8
9//usage:#define taskset_trivial_usage
10//usage:       "[-p] [MASK] [PID | PROG ARGS]"
11//usage:#define taskset_full_usage "\n\n"
12//usage:       "Set or get CPU affinity\n"
13//usage:     "\n    -p  Operate on an existing PID"
14//usage:
15//usage:#define taskset_example_usage
16//usage:       "$ taskset 0x7 ./dgemm_test&\n"
17//usage:       "$ taskset -p 0x1 $!\n"
18//usage:       "pid 4790's current affinity mask: 7\n"
19//usage:       "pid 4790's new affinity mask: 1\n"
20//usage:       "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n"
21//usage:       "pid 6671's current affinity mask: 1\n"
22//usage:       "pid 6671's new affinity mask: 1\n"
23//usage:       "$ taskset -p 1\n"
24//usage:       "pid 1's current affinity mask: 3\n"
25
26#include <sched.h>
27#include "libbb.h"
28
29#if ENABLE_FEATURE_TASKSET_FANCY
30#define TASKSET_PRINTF_MASK "%s"
31/* craft a string from the mask */
32static char *from_cpuset(cpu_set_t *mask)
33{
34    int i;
35    char *ret = NULL;
36    char *str = xzalloc((CPU_SETSIZE / 4) + 1); /* we will leak it */
37
38    for (i = CPU_SETSIZE - 4; i >= 0; i -= 4) {
39        int val = 0;
40        int off;
41        for (off = 0; off <= 3; ++off)
42            if (CPU_ISSET(i + off, mask))
43                val |= 1 << off;
44        if (!ret && val)
45            ret = str;
46        *str++ = bb_hexdigits_upcase[val] | 0x20;
47    }
48    return ret;
49}
50#else
51#define TASKSET_PRINTF_MASK "%llx"
52static unsigned long long from_cpuset(cpu_set_t *mask)
53{
54    struct BUG_CPU_SETSIZE_is_too_small {
55        char BUG_CPU_SETSIZE_is_too_small[
56            CPU_SETSIZE < sizeof(int) ? -1 : 1];
57    };
58    char *p = (void*)mask;
59
60    /* Take the least significant bits. Careful!
61     * Consider both CPU_SETSIZE=4 and CPU_SETSIZE=1024 cases
62     */
63#if BB_BIG_ENDIAN
64    /* For big endian, it means LAST bits */
65    if (CPU_SETSIZE < sizeof(long))
66        p += CPU_SETSIZE - sizeof(int);
67    else if (CPU_SETSIZE < sizeof(long long))
68        p += CPU_SETSIZE - sizeof(long);
69    else
70        p += CPU_SETSIZE - sizeof(long long);
71#endif
72    if (CPU_SETSIZE < sizeof(long))
73        return *(unsigned*)p;
74    if (CPU_SETSIZE < sizeof(long long))
75        return *(unsigned long*)p;
76    return *(unsigned long long*)p;
77}
78#endif
79
80
81int taskset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
82int taskset_main(int argc UNUSED_PARAM, char **argv)
83{
84    cpu_set_t mask;
85    pid_t pid = 0;
86    unsigned opt_p;
87    const char *current_new;
88    char *pid_str;
89    char *aff = aff; /* for compiler */
90
91    /* NB: we mimic util-linux's taskset: -p does not take
92     * an argument, i.e., "-pN" is NOT valid, only "-p N"!
93     * Indeed, util-linux-2.13-pre7 uses:
94     * getopt_long(argc, argv, "+pchV", ...), not "...p:..." */
95
96    opt_complementary = "-1"; /* at least 1 arg */
97    opt_p = getopt32(argv, "+p");
98    argv += optind;
99
100    if (opt_p) {
101        pid_str = *argv++;
102        if (*argv) { /* "-p <aff> <pid> ...rest.is.ignored..." */
103            aff = pid_str;
104            pid_str = *argv; /* NB: *argv != NULL in this case */
105        }
106        /* else it was just "-p <pid>", and *argv == NULL */
107        pid = xatoul_range(pid_str, 1, ((unsigned)(pid_t)ULONG_MAX) >> 1);
108    } else {
109        aff = *argv++; /* <aff> <cmd...> */
110        if (!*argv)
111            bb_show_usage();
112    }
113
114    current_new = "current\0new";
115    if (opt_p) {
116 print_aff:
117        if (sched_getaffinity(pid, sizeof(mask), &mask) < 0)
118            bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid);
119        printf("pid %d's %s affinity mask: "TASKSET_PRINTF_MASK"\n",
120                pid, current_new, from_cpuset(&mask));
121        if (!*argv) {
122            /* Either it was just "-p <pid>",
123             * or it was "-p <aff> <pid>" and we came here
124             * for the second time (see goto below) */
125            return EXIT_SUCCESS;
126        }
127        *argv = NULL;
128        current_new += 8; /* "new" */
129    }
130
131    { /* Affinity was specified, translate it into cpu_set_t */
132        unsigned i;
133        /* Do not allow zero mask: */
134        unsigned long long m = xstrtoull_range(aff, 0, 1, ULLONG_MAX);
135        enum { CNT_BIT = CPU_SETSIZE < sizeof(m)*8 ? CPU_SETSIZE : sizeof(m)*8 };
136
137        CPU_ZERO(&mask);
138        for (i = 0; i < CNT_BIT; i++) {
139            unsigned long long bit = (1ULL << i);
140            if (bit & m)
141                CPU_SET(i, &mask);
142        }
143    }
144
145    /* Set pid's or our own (pid==0) affinity */
146    if (sched_setaffinity(pid, sizeof(mask), &mask))
147        bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid);
148
149    if (!argv[0]) /* "-p <aff> <pid> [...ignored...]" */
150        goto print_aff; /* print new affinity and exit */
151
152    BB_EXECVP_or_die(argv);
153}
Note: See TracBrowser for help on using the repository browser.