blob: e76fb52286bbbb078049d336ad45ed3491a6d95a [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/emulation/nand_limits.h"
#include "android/utils/debug.h"
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#define T(...) VERBOSE_PRINT(nand_limits, __VA_ARGS__)
static bool parse_nand_rw_limit(const char* value,
const char* value_end,
uint64_t* v) {
char* end;
uint64_t val = strtoul(value, &end, 0);
if (end == value) {
derror("bad parameter value '%s': expecting unsigned integer", value);
return false;
}
switch (end[0]) {
case 'K':
val <<= 10;
break;
case 'M':
val <<= 20;
break;
case 'G':
val <<= 30;
break;
case 0:
case ',':
break;
default:
derror("bad read/write limit suffix: use K, M or G, got [%s]", end);
return false;
}
*v = val;
return true;
}
bool android_nand_limits_parse(const char* limits,
AndroidNandLimit* read_limit,
AndroidNandLimit* write_limit) {
int pid = -1, signal = -1;
uint64_t reads = 0, writes = 0;
const char* item = limits;
#ifdef _WIN32
// Currently not working on Windows.
derror("-nand-limits is not available on Windows!");
return false;
#endif
/* parse over comma-separated items */
while (item && *item) {
const char* next_item;
const char* comma = strchr(item, ',');
char* end;
if (!comma) {
next_item = item + strlen(item);
comma = next_item;
} else {
next_item = comma + 1;
}
if (!strncmp(item, "pid=", 4)) {
pid = strtol(item + 4, &end, 10);
if (end != comma) {
derror("bad parameter, expecting pid=<number>, got '%s'", item);
return false;
}
if (pid <= 0) {
derror("bad parameter: process identifier must be > 0");
return false;
}
} else if (!strncmp(item, "signal=", 7)) {
signal = strtol(item + 7, &end, 10);
if (end != comma) {
derror("bad parameter: expecting signal=<number>, got '%s'",
item);
return false;
}
if (signal <= 0) {
derror("bad parameter: signal number must be > 0");
return false;
}
} else if (!strncmp(item, "reads=", 6)) {
if (!parse_nand_rw_limit(item + 6, next_item, &reads)) {
return false;
}
} else if (!strncmp(item, "writes=", 7)) {
if (!parse_nand_rw_limit(item + 7, next_item, &writes)) {
return false;
}
} else {
derror("bad parameter '%s' (see -help-nand-limits)", item);
return false;
}
item = next_item;
}
if (pid < 0) {
derror("bad paramater: missing pid=<number>");
return false;
} else if (signal < 0) {
derror("bad parameter: missing signal=<number>");
return false;
} else if (reads == 0 && writes == 0) {
dwarning("no read or write limit specified. ignoring -nand-limits");
return false;
}
read_limit->pid = pid;
read_limit->signal = signal;
read_limit->counter = 0;
read_limit->limit = reads;
write_limit->pid = pid;
write_limit->signal = signal;
write_limit->counter = 0;
write_limit->limit = writes;
return true;
}
void android_nand_limit_update(AndroidNandLimit* l, uint32_t count) {
if (l->counter >= l->limit) {
return;
}
uint64_t avail = l->limit - l->counter;
if (avail > count) {
avail = count;
}
if (l->counter == 0) {
T("%s: starting threshold counting to %lld", __FUNCTION__, l->limit);
}
l->counter += avail;
if (l->counter >= l->limit) {
/* threshold reach, send a signal to an external process */
T("%s: sending signal %d to pid %d !", __FUNCTION__, l->signal, l->pid);
#ifndef _WIN32
// Currently not working on Windows.
kill(l->pid, l->signal);
#endif
}
return;
}