1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
#pragma once
#include <stdexcept>
#include "logger.h"
namespace libsinsp
{
/**
* Simple helper to read a comma-separated list that includes ranges and
* determine the total count of the values within.
* Examples: 1,4-5 = 3; 0-15 = 16; 3,7,11 = 3
*
* See the "List Format" section of
* http://man7.org/linux/man-pages/man7/cpuset.7.html
*
* Returns -1 if string is invalid.
*/
class cgroup_list_counter
{
public:
const int INVALID_CPU_COUNT = -1;
/**
* Return the number of elements given by the buffer. If needed, log at the
* given log-level.
*/
int operator ()(const char *buffer)
{
reset();
int cpu_count = 0;
try
{
const char *position = buffer;
for(; '\0' != *position; ++position)
{
if ('-' == *position)
{
if (nullptr == m_section_start)
{
throw std::runtime_error("duplicate range indicator before start");
}
if (nullptr != m_range_indicator)
{
throw std::runtime_error("duplicate range indicators");
}
m_range_indicator = position;
}
else if (',' == *position)
{
cpu_count += process_section(m_section_start, position, m_range_indicator);
reset();
}
else if (nullptr == m_section_start)
{
m_section_start = position;
}
}
// There is never a trailing comma so always process the
// final section
cpu_count += process_section(m_section_start, position, m_range_indicator);
}
catch (const std::exception& ex)
{
g_logger.format(sinsp_logger::SEV_ERROR,
"Invalid List Format: %s. Detail: %s",
buffer,
ex.what());
return INVALID_CPU_COUNT;
}
return cpu_count;
}
private:
static int process_number(const char *section_start, const char *section_end)
{
std::string section(section_start, section_end - section_start);
return std::stoi(section.c_str());
}
static int process_section(const char *section_start, const char *section_end, const char *range_indicator)
{
if (nullptr == section_start)
{
throw std::runtime_error("invalid end of section before start of section");
}
if (nullptr == section_end)
{
throw std::runtime_error("invalid end of section");
}
if (section_end <= section_start)
{
throw std::runtime_error("invalid section");
}
if (range_indicator)
{
// Split into two sections
int first = process_number(section_start, range_indicator);
int second = process_number(range_indicator + 1, section_end);
if (second <= first)
{
throw std::runtime_error("invalid range");
}
return second - first + 1;
}
// We don't care what the value is, we just want to know that it is a number
(void)process_number(section_start, section_end);
return 1;
}
void reset()
{
m_section_start = nullptr;
m_range_indicator = nullptr;
}
const char *m_section_start = nullptr;
const char *m_range_indicator = nullptr;
};
}
|