CPUMeter: avoid crashes and leaks in case the CPU count changes

E.g. if the HT/SMT mode changes

Use separate data for sub-meters
Do not reuse drawData for maintainability
This commit is contained in:
Christian Göttsche 2020-09-23 11:58:11 +02:00 committed by cgzones
parent 0b9a001498
commit 9f5b50edd7
2 changed files with 39 additions and 19 deletions

View File

@ -27,6 +27,11 @@ static const int CPUMeter_attributes[] = {
CPU_IOWAIT CPU_IOWAIT
}; };
typedef struct CPUMeterData_ {
int cpus;
Meter** meters;
} CPUMeterData;
static void CPUMeter_init(Meter* this) { static void CPUMeter_init(Meter* this) {
int cpu = this->param; int cpu = this->param;
if (this->pl->cpuCount > 1) { if (this->pl->cpuCount > 1) {
@ -42,6 +47,9 @@ static void CPUMeter_updateValues(Meter* this, char* buffer, int size) {
int cpu = this->param; int cpu = this->param;
if (cpu > this->pl->cpuCount) { if (cpu > this->pl->cpuCount) {
xSnprintf(buffer, size, "absent"); xSnprintf(buffer, size, "absent");
int items = this->curItems;
for (int i = 0; i < items; i++)
this->values[i] = 0;
return; return;
} }
memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT); memset(this->values, 0, sizeof(double) * CPU_METER_ITEMCOUNT);
@ -119,7 +127,8 @@ static void CPUMeter_display(const Object* cast, RichString* out) {
} }
static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) { static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
int cpus = this->pl->cpuCount; CPUMeterData* data = this->meterData;
int cpus = data->cpus;
switch(Meter_name(this)[0]) { switch(Meter_name(this)[0]) {
default: default:
case 'A': // All case 'A': // All
@ -139,9 +148,13 @@ static void AllCPUsMeter_getRange(Meter* this, int* start, int* count) {
static void CPUMeterCommonInit(Meter *this, int ncol) { static void CPUMeterCommonInit(Meter *this, int ncol) {
int cpus = this->pl->cpuCount; int cpus = this->pl->cpuCount;
if (!this->drawData) CPUMeterData* data = this->meterData;
this->drawData = xCalloc(cpus, sizeof(Meter*)); if (!data) {
Meter** meters = (Meter**) this->drawData; data = this->meterData = xMalloc(sizeof(CPUMeterData));
data->cpus = cpus;
data->meters = xCalloc(cpus, sizeof(Meter*));
}
Meter** meters = data->meters;
int start, count; int start, count;
AllCPUsMeter_getRange(this, &start, &count); AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@ -156,7 +169,8 @@ static void CPUMeterCommonInit(Meter *this, int ncol) {
} }
static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) { static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
Meter** meters = (Meter**) this->drawData; CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
this->mode = mode; this->mode = mode;
int h = Meter_modes[mode]->h; int h = Meter_modes[mode]->h;
int start, count; int start, count;
@ -168,11 +182,14 @@ static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) {
} }
static void AllCPUsMeter_done(Meter* this) { static void AllCPUsMeter_done(Meter* this) {
Meter** meters = (Meter**) this->drawData; CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count; int start, count;
AllCPUsMeter_getRange(this, &start, &count); AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
Meter_delete((Object*)meters[i]); Meter_delete((Object*)meters[i]);
free(data->meters);
free(data);
} }
static void SingleColCPUsMeter_init(Meter* this) { static void SingleColCPUsMeter_init(Meter* this) {
@ -208,18 +225,19 @@ static void OctoColCPUsMeter_updateMode(Meter* this, int mode) {
} }
static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) { static void CPUMeterCommonDraw(Meter* this, int x, int y, int w, int ncol) {
Meter** meters = (Meter**) this->drawData; CPUMeterData* data = this->meterData;
int start, count; Meter** meters = data->meters;
AllCPUsMeter_getRange(this, &start, &count); int start, count;
int colwidth = (w-ncol)/ncol + 1; AllCPUsMeter_getRange(this, &start, &count);
int diff = (w - (colwidth * ncol)); int colwidth = (w-ncol)/ncol + 1;
int nrows = (count + ncol - 1) / ncol; int diff = (w - (colwidth * ncol));
for (int i = 0; i < count; i++){ int nrows = (count + ncol - 1) / ncol;
int d = (i/nrows) > diff ? diff : (i / nrows) ; // dynamic spacer for (int i = 0; i < count; i++){
int xpos = x + ((i / nrows) * colwidth) + d; int d = (i/nrows) > diff ? diff : (i / nrows) ; // dynamic spacer
int ypos = y + ((i % nrows) * meters[0]->h); int xpos = x + ((i / nrows) * colwidth) + d;
meters[i]->draw(meters[i], xpos, ypos, colwidth); int ypos = y + ((i % nrows) * meters[0]->h);
} meters[i]->draw(meters[i], xpos, ypos, colwidth);
}
} }
static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) { static void DualColCPUsMeter_draw(Meter* this, int x, int y, int w) {
@ -236,7 +254,8 @@ static void OctoColCPUsMeter_draw(Meter* this, int x, int y, int w) {
static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) { static void SingleColCPUsMeter_draw(Meter* this, int x, int y, int w) {
Meter** meters = (Meter**) this->drawData; CPUMeterData* data = this->meterData;
Meter** meters = data->meters;
int start, count; int start, count;
AllCPUsMeter_getRange(this, &start, &count); AllCPUsMeter_getRange(this, &start, &count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {

View File

@ -71,6 +71,7 @@ struct Meter_ {
char curItems; char curItems;
double* values; double* values;
double total; double total;
void* meterData;
}; };
typedef struct MeterMode_ { typedef struct MeterMode_ {