60d487877a
Declaractions for those functions already have dst and src as param names, but definitions use set1 and set2, which doesn't really tell which one is which. My IDE actually gives me tooltips with param names from definitions and it would be much easier to see "dst" and "src" in there. Change-Id: I45013cf27fc95f69cb2c776fb1b6701c5e60e373 Signed-off-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/455163 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
342 lines
7.4 KiB
C
342 lines
7.4 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright(c) Intel Corporation. All rights reserved.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "spdk/cpuset.h"
|
|
#include "spdk/log.h"
|
|
|
|
struct spdk_cpuset {
|
|
char str[SPDK_CPUSET_SIZE / 4 + 1];
|
|
uint8_t cpus[SPDK_CPUSET_SIZE / 8];
|
|
};
|
|
|
|
struct spdk_cpuset *
|
|
spdk_cpuset_alloc(void)
|
|
{
|
|
return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1);
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_free(struct spdk_cpuset *set)
|
|
{
|
|
free(set);
|
|
}
|
|
|
|
bool
|
|
spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
|
|
{
|
|
assert(set1 != NULL);
|
|
assert(set2 != NULL);
|
|
return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
|
|
{
|
|
assert(dst != NULL);
|
|
assert(src != NULL);
|
|
memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_negate(struct spdk_cpuset *set)
|
|
{
|
|
unsigned int i;
|
|
assert(set != NULL);
|
|
for (i = 0; i < sizeof(set->cpus); i++) {
|
|
set->cpus[i] = ~set->cpus[i];
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
|
|
{
|
|
unsigned int i;
|
|
assert(dst != NULL);
|
|
assert(src != NULL);
|
|
for (i = 0; i < sizeof(src->cpus); i++) {
|
|
dst->cpus[i] &= src->cpus[i];
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
|
|
{
|
|
unsigned int i;
|
|
assert(dst != NULL);
|
|
assert(src != NULL);
|
|
for (i = 0; i < sizeof(src->cpus); i++) {
|
|
dst->cpus[i] |= src->cpus[i];
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
|
|
{
|
|
unsigned int i;
|
|
assert(dst != NULL);
|
|
assert(src != NULL);
|
|
for (i = 0; i < sizeof(src->cpus); i++) {
|
|
dst->cpus[i] ^= src->cpus[i];
|
|
}
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_zero(struct spdk_cpuset *set)
|
|
{
|
|
assert(set != NULL);
|
|
memset(set->cpus, 0, sizeof(set->cpus));
|
|
}
|
|
|
|
void
|
|
spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
|
|
{
|
|
assert(set != NULL);
|
|
assert(cpu < sizeof(set->cpus) * 8);
|
|
if (state) {
|
|
set->cpus[cpu / 8] |= (1U << (cpu % 8));
|
|
} else {
|
|
set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
|
|
}
|
|
}
|
|
|
|
bool
|
|
spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
|
|
{
|
|
assert(set != NULL);
|
|
assert(cpu < sizeof(set->cpus) * 8);
|
|
return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
|
|
}
|
|
|
|
uint32_t
|
|
spdk_cpuset_count(const struct spdk_cpuset *set)
|
|
{
|
|
uint32_t count = 0;
|
|
uint8_t n;
|
|
unsigned int i;
|
|
for (i = 0; i < sizeof(set->cpus); i++) {
|
|
n = set->cpus[i];
|
|
while (n) {
|
|
n &= (n - 1);
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
const char *
|
|
spdk_cpuset_fmt(struct spdk_cpuset *set)
|
|
{
|
|
uint32_t lcore, lcore_max = 0;
|
|
int val, i, n;
|
|
char *ptr;
|
|
static const char *hex = "0123456789abcdef";
|
|
|
|
assert(set != NULL);
|
|
|
|
for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
|
|
if (spdk_cpuset_get_cpu(set, lcore)) {
|
|
lcore_max = lcore;
|
|
}
|
|
}
|
|
|
|
ptr = set->str;
|
|
n = lcore_max / 8;
|
|
val = set->cpus[n];
|
|
|
|
/* Store first number only if it is not leading zero */
|
|
if ((val & 0xf0) != 0) {
|
|
*(ptr++) = hex[(val & 0xf0) >> 4];
|
|
}
|
|
*(ptr++) = hex[val & 0x0f];
|
|
|
|
for (i = n - 1; i >= 0; i--) {
|
|
val = set->cpus[i];
|
|
*(ptr++) = hex[(val & 0xf0) >> 4];
|
|
*(ptr++) = hex[val & 0x0f];
|
|
}
|
|
*ptr = '\0';
|
|
|
|
return set->str;
|
|
}
|
|
|
|
static int
|
|
hex_value(uint8_t c)
|
|
{
|
|
#define V(x, y) [x] = y + 1
|
|
static const int8_t val[256] = {
|
|
V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
|
|
V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
|
|
V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
|
|
V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
|
|
};
|
|
#undef V
|
|
|
|
return val[c] - 1;
|
|
}
|
|
|
|
static int
|
|
parse_list(const char *mask, struct spdk_cpuset *set)
|
|
{
|
|
char *end;
|
|
const char *ptr = mask;
|
|
uint32_t lcore;
|
|
uint32_t lcore_min, lcore_max;
|
|
|
|
spdk_cpuset_zero(set);
|
|
lcore_min = UINT32_MAX;
|
|
|
|
ptr++;
|
|
end = (char *)ptr;
|
|
do {
|
|
while (isblank(*ptr)) {
|
|
ptr++;
|
|
}
|
|
if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
|
|
goto invalid_character;
|
|
}
|
|
|
|
errno = 0;
|
|
lcore = strtoul(ptr, &end, 10);
|
|
if (errno) {
|
|
SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
|
|
return -1;
|
|
}
|
|
|
|
if (lcore >= sizeof(set->cpus) * 8) {
|
|
SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
|
|
return -1;
|
|
}
|
|
|
|
while (isblank(*end)) {
|
|
end++;
|
|
}
|
|
|
|
if (*end == '-') {
|
|
lcore_min = lcore;
|
|
} else if (*end == ',' || *end == ']') {
|
|
lcore_max = lcore;
|
|
if (lcore_min == UINT32_MAX) {
|
|
lcore_min = lcore;
|
|
}
|
|
if (lcore_min > lcore_max) {
|
|
SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
|
|
lcore_min, lcore_max);
|
|
return -1;
|
|
}
|
|
for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
|
|
spdk_cpuset_set_cpu(set, lcore, true);
|
|
}
|
|
lcore_min = UINT32_MAX;
|
|
} else {
|
|
goto invalid_character;
|
|
}
|
|
|
|
ptr = end + 1;
|
|
|
|
} while (*end != ']');
|
|
|
|
return 0;
|
|
|
|
invalid_character:
|
|
if (*end == '\0') {
|
|
SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
|
|
} else {
|
|
SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
|
|
{
|
|
int i, j;
|
|
char c;
|
|
int val;
|
|
uint32_t lcore = 0;
|
|
|
|
if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
|
|
mask += 2;
|
|
len -= 2;
|
|
}
|
|
|
|
spdk_cpuset_zero(set);
|
|
for (i = len - 1; i >= 0; i--) {
|
|
c = mask[i];
|
|
val = hex_value(c);
|
|
if (val < 0) {
|
|
/* Invalid character */
|
|
SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
|
|
return -1;
|
|
}
|
|
for (j = 0; j < 4 && lcore < sizeof(set->cpus); j++, lcore++) {
|
|
if ((1 << j) & val) {
|
|
spdk_cpuset_set_cpu(set, lcore, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
|
|
{
|
|
int ret;
|
|
size_t len;
|
|
|
|
if (mask == NULL || set == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
while (isblank(*mask)) {
|
|
mask++;
|
|
}
|
|
|
|
len = strlen(mask);
|
|
while (len > 0 && isblank(mask[len - 1])) {
|
|
len--;
|
|
}
|
|
|
|
if (len == 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (mask[0] == '[') {
|
|
ret = parse_list(mask, set);
|
|
} else {
|
|
ret = parse_mask(mask, set, len);
|
|
}
|
|
|
|
return ret;
|
|
}
|