mirror of
https://dev.iopsys.eu/system/sysmngr.git
synced 2025-12-10 08:14:38 +01:00
Add support to sort processes by 'PID', 'Memory' and 'CPU_Time'
This commit is contained in:
parent
ea11440212
commit
865e04512f
2 changed files with 204 additions and 16 deletions
217
src/processes.c
217
src/processes.c
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <libbbfdm-api/bbfdm_api.h>
|
#include <libbbfdm-api/bbfdm_api.h>
|
||||||
|
|
||||||
|
#define MAX_PROCESS_ENTRIES BBF_MAX_OBJECT_INSTANCES
|
||||||
#define DEFAULT_CPU_NAME "cpu"
|
#define DEFAULT_CPU_NAME "cpu"
|
||||||
#define DEFAULT_CPU_POLL_INTERVAL "5"
|
#define DEFAULT_CPU_POLL_INTERVAL "5"
|
||||||
#define DEFAULT_CPU_NUM_SAMPLES "30"
|
#define DEFAULT_CPU_NUM_SAMPLES "30"
|
||||||
|
|
@ -24,6 +25,10 @@
|
||||||
typedef struct process_entry {
|
typedef struct process_entry {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
|
unsigned long pid_raw;
|
||||||
|
unsigned long vsize_raw;
|
||||||
|
unsigned long cpu_time_raw;
|
||||||
|
|
||||||
char command[256];
|
char command[256];
|
||||||
char state[16];
|
char state[16];
|
||||||
char pid[8];
|
char pid[8];
|
||||||
|
|
@ -41,12 +46,20 @@ typedef struct jiffy_counts_t {
|
||||||
unsigned long long busy_time;
|
unsigned long long busy_time;
|
||||||
} jiffy_counts_t;
|
} jiffy_counts_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SORT_BY_PID,
|
||||||
|
SORT_BY_MEMORY,
|
||||||
|
SORT_BY_CPU_TIME,
|
||||||
|
/* SORT_BY_CPU_Usage */
|
||||||
|
} process_sorting_method_t;
|
||||||
|
|
||||||
typedef struct process_ctx {
|
typedef struct process_ctx {
|
||||||
struct ubus_context *ubus_ctx;
|
struct ubus_context *ubus_ctx;
|
||||||
struct uloop_timeout instance_timer;
|
struct uloop_timeout instance_timer;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int refresh_interval;
|
int refresh_interval;
|
||||||
int max_entries;
|
int max_entries;
|
||||||
|
process_sorting_method_t sorting_method;
|
||||||
} process_ctx;
|
} process_ctx;
|
||||||
|
|
||||||
typedef struct cpu_info {
|
typedef struct cpu_info {
|
||||||
|
|
@ -72,9 +85,46 @@ typedef struct cpu_info {
|
||||||
static process_ctx g_process_ctx = {0};
|
static process_ctx g_process_ctx = {0};
|
||||||
static cpu_info_t g_cpu_info = {0};
|
static cpu_info_t g_cpu_info = {0};
|
||||||
|
|
||||||
|
static char *ProcessSupportedSortingMethods[] = {"PID", "Memory", "CPU_Time", /* "CPU_Usage", */ NULL};
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* COMMON FUNCTIONS
|
* COMMON FUNCTIONS
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
static process_sorting_method_t str_to_sorting_method(const char *str)
|
||||||
|
{
|
||||||
|
if (!str)
|
||||||
|
return SORT_BY_PID;
|
||||||
|
|
||||||
|
if (strcasecmp(str, ProcessSupportedSortingMethods[0]) == 0)
|
||||||
|
return SORT_BY_PID;
|
||||||
|
else if (strcasecmp(str, ProcessSupportedSortingMethods[1]) == 0)
|
||||||
|
return SORT_BY_MEMORY;
|
||||||
|
else if (strcasecmp(str, ProcessSupportedSortingMethods[2]) == 0)
|
||||||
|
return SORT_BY_CPU_TIME;
|
||||||
|
/*
|
||||||
|
else if (strcasecmp(str, ProcessSupportedSortingMethods[3]) == 0)
|
||||||
|
return SORT_BY_CPU_Usage;
|
||||||
|
*/
|
||||||
|
return SORT_BY_PID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *sorting_method_to_str(process_sorting_method_t key)
|
||||||
|
{
|
||||||
|
switch (key) {
|
||||||
|
case SORT_BY_MEMORY:
|
||||||
|
return ProcessSupportedSortingMethods[1];
|
||||||
|
case SORT_BY_CPU_TIME:
|
||||||
|
return ProcessSupportedSortingMethods[2];
|
||||||
|
/*
|
||||||
|
case SORT_BY_CPU_Usage:
|
||||||
|
return ProcessSupportedSortingMethods[3];
|
||||||
|
*/
|
||||||
|
case SORT_BY_PID:
|
||||||
|
default:
|
||||||
|
return ProcessSupportedSortingMethods[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void get_jif_val(jiffy_counts_t *p_jif)
|
static void get_jif_val(jiffy_counts_t *p_jif)
|
||||||
{
|
{
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
|
|
@ -221,23 +271,37 @@ static int filter_process_dirs(const struct dirent *entry)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison function for scandir to sort numerically
|
static int compare_by_pid(const void *a, const void *b)
|
||||||
static int numeric_sort(const struct dirent **a, const struct dirent **b)
|
|
||||||
{
|
{
|
||||||
long num1 = strtol((*a)->d_name, NULL, 10);
|
const process_entry *pa = *(const process_entry **)a;
|
||||||
long num2 = strtol((*b)->d_name, NULL, 10);
|
const process_entry *pb = *(const process_entry **)b;
|
||||||
return num1 - num2;
|
return (int)(pb->pid_raw - pa->pid_raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_by_cpu_time(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const process_entry *pa = *(const process_entry **)a;
|
||||||
|
const process_entry *pb = *(const process_entry **)b;
|
||||||
|
return (int)(pb->cpu_time_raw - pa->cpu_time_raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_by_memory(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const process_entry *pa = *(const process_entry **)a;
|
||||||
|
const process_entry *pb = *(const process_entry **)b;
|
||||||
|
return (int)(pb->vsize_raw - pa->vsize_raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_process_list(void)
|
static void init_process_list(void)
|
||||||
{
|
{
|
||||||
struct dirent **namelist = NULL;
|
struct dirent **namelist = NULL;
|
||||||
|
process_entry *process_entries[MAX_PROCESS_ENTRIES];
|
||||||
int process_num = 0;
|
int process_num = 0;
|
||||||
|
|
||||||
BBFDM_INFO("Init process list");
|
BBFDM_INFO("Init process list");
|
||||||
|
|
||||||
// Scan '/proc' for numeric directories
|
// Scan '/proc' for numeric directories
|
||||||
int count = scandir("/proc", &namelist, filter_process_dirs, numeric_sort);
|
int count = scandir("/proc", &namelist, filter_process_dirs, NULL);
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
BBFDM_ERR("Error getting process list");
|
BBFDM_ERR("Error getting process list");
|
||||||
return;
|
return;
|
||||||
|
|
@ -245,19 +309,19 @@ static void init_process_list(void)
|
||||||
|
|
||||||
BBFDM_DEBUG("Process Number: '%d'", count);
|
BBFDM_DEBUG("Process Number: '%d'", count);
|
||||||
|
|
||||||
for (int i = count - 1; i >= 0; i--) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
|
||||||
|
if (process_num >= MAX_PROCESS_ENTRIES) {
|
||||||
|
FREE(namelist[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct stat stats = {0};
|
struct stat stats = {0};
|
||||||
char buf[1024], fstat[288], command[256], comm[32];
|
char buf[1024], fstat[288], command[256], comm[32];
|
||||||
char bsize[32], cputime[32], priori[32], state;
|
char bsize[32], cputime[32], priori[32], state;
|
||||||
unsigned long stime, utime, vsize;
|
unsigned long stime, utime, vsize;
|
||||||
int priority, n;
|
int priority, n;
|
||||||
|
|
||||||
// Handle max_entries limits (negative means show all)
|
|
||||||
if (g_process_ctx.max_entries >= 0 && process_num >= g_process_ctx.max_entries) {
|
|
||||||
FREE(namelist[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(fstat, sizeof(fstat), "/proc/%s/stat", namelist[i]->d_name);
|
snprintf(fstat, sizeof(fstat), "/proc/%s/stat", namelist[i]->d_name);
|
||||||
if (stat(fstat, &stats)) {
|
if (stat(fstat, &stats)) {
|
||||||
FREE(namelist[i]);
|
FREE(namelist[i]);
|
||||||
|
|
@ -320,8 +384,6 @@ static void init_process_list(void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&pentry->list, &g_process_ctx.list);
|
|
||||||
|
|
||||||
DM_STRNCPY(pentry->pid, namelist[i]->d_name, sizeof(pentry->pid));
|
DM_STRNCPY(pentry->pid, namelist[i]->d_name, sizeof(pentry->pid));
|
||||||
DM_STRNCPY(pentry->command, command, sizeof(pentry->command));
|
DM_STRNCPY(pentry->command, command, sizeof(pentry->command));
|
||||||
DM_STRNCPY(pentry->size, bsize, sizeof(pentry->size));
|
DM_STRNCPY(pentry->size, bsize, sizeof(pentry->size));
|
||||||
|
|
@ -329,12 +391,50 @@ static void init_process_list(void)
|
||||||
DM_STRNCPY(pentry->cputime, cputime, sizeof(pentry->cputime));
|
DM_STRNCPY(pentry->cputime, cputime, sizeof(pentry->cputime));
|
||||||
DM_STRNCPY(pentry->state, get_proc_state(state), sizeof(pentry->state));
|
DM_STRNCPY(pentry->state, get_proc_state(state), sizeof(pentry->state));
|
||||||
|
|
||||||
process_num++;
|
// store raw values
|
||||||
|
pentry->cpu_time_raw = utime + stime;
|
||||||
|
pentry->vsize_raw = vsize;
|
||||||
|
pentry->pid_raw = strtoul(namelist[i]->d_name, NULL, 10);
|
||||||
|
|
||||||
|
process_entries[process_num++] = pentry;
|
||||||
|
|
||||||
FREE(namelist[i]);
|
FREE(namelist[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
FREE(namelist);
|
FREE(namelist);
|
||||||
|
|
||||||
|
// Sort entries based on configuration
|
||||||
|
switch (g_process_ctx.sorting_method) {
|
||||||
|
case SORT_BY_MEMORY:
|
||||||
|
qsort(process_entries, process_num, sizeof(process_entry *), compare_by_memory);
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
case SORT_BY_CPU_Usage:
|
||||||
|
qsort(process_entries, process_num, sizeof(process_entry *), compare_by_cpu_usage);
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case SORT_BY_CPU_TIME:
|
||||||
|
qsort(process_entries, process_num, sizeof(process_entry *), compare_by_cpu_time);
|
||||||
|
break;
|
||||||
|
case SORT_BY_PID:
|
||||||
|
default:
|
||||||
|
qsort(process_entries, process_num, sizeof(process_entry *), compare_by_pid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sorted entries to the global list
|
||||||
|
int process_count = 0;
|
||||||
|
for (int i = 0; i < process_num; i++) {
|
||||||
|
|
||||||
|
// Handle max_entries limits (negative means show all)
|
||||||
|
if (g_process_ctx.max_entries >= 0 && process_count >= g_process_ctx.max_entries) {
|
||||||
|
FREE(process_entries[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&process_entries[i]->list, &g_process_ctx.list);
|
||||||
|
process_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_process_list(void)
|
static void free_process_list(void)
|
||||||
|
|
@ -358,6 +458,15 @@ static int get_maximum_process_entries(void)
|
||||||
return (int)strtol(buf, NULL, 10);
|
return (int)strtol(buf, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static process_sorting_method_t get_process_sorting_method(void)
|
||||||
|
{
|
||||||
|
char buf[32] = {0};
|
||||||
|
|
||||||
|
BBFDM_UCI_GET("sysmngr", "process", "sorting_method", "PID", buf, sizeof(buf));
|
||||||
|
|
||||||
|
return str_to_sorting_method(buf);
|
||||||
|
}
|
||||||
|
|
||||||
static int get_instance_refresh_interval(void)
|
static int get_instance_refresh_interval(void)
|
||||||
{
|
{
|
||||||
char buf[8] = {0};
|
char buf[8] = {0};
|
||||||
|
|
@ -581,8 +690,16 @@ static void free_global_cpu_info(void)
|
||||||
void sysmngr_process_init(struct ubus_context *ubus_ctx)
|
void sysmngr_process_init(struct ubus_context *ubus_ctx)
|
||||||
{
|
{
|
||||||
g_process_ctx.ubus_ctx = ubus_ctx;
|
g_process_ctx.ubus_ctx = ubus_ctx;
|
||||||
|
|
||||||
g_process_ctx.max_entries = get_maximum_process_entries();
|
g_process_ctx.max_entries = get_maximum_process_entries();
|
||||||
|
BBFDM_DEBUG("Process Config: |Max Entries| |%d|", g_process_ctx.max_entries);
|
||||||
|
|
||||||
|
g_process_ctx.sorting_method = get_process_sorting_method();
|
||||||
|
BBFDM_DEBUG("Process Config: |Sorting Method| |%s|", sorting_method_to_str(g_process_ctx.sorting_method));
|
||||||
|
|
||||||
g_process_ctx.refresh_interval = get_instance_refresh_interval();
|
g_process_ctx.refresh_interval = get_instance_refresh_interval();
|
||||||
|
BBFDM_DEBUG("Process Config: |Refresh Interval| |%d|", g_process_ctx.refresh_interval);
|
||||||
|
|
||||||
g_process_ctx.instance_timer.cb = process_refresh_instance_timer;
|
g_process_ctx.instance_timer.cb = process_refresh_instance_timer;
|
||||||
INIT_LIST_HEAD(&g_process_ctx.list);
|
INIT_LIST_HEAD(&g_process_ctx.list);
|
||||||
|
|
||||||
|
|
@ -987,6 +1104,67 @@ static int set_DeviceInfoProcessStatusCPU_FilePath(char *refparam, struct dmctx
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_VENDOR_EXTENSIONS
|
||||||
|
static int get_process_supported_sorting_methods(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
char buf[64] = {0};
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (int i = 0; ProcessSupportedSortingMethods[i] != NULL; i++) {
|
||||||
|
pos += snprintf(&buf[pos], sizeof(buf) - pos, "%s%s",
|
||||||
|
(i > 0) ? "," : "",
|
||||||
|
ProcessSupportedSortingMethods[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = dmstrdup(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_process_current_sorting_method(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "process", "sorting_method", "PID");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_process_current_sorting_method(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
if (bbfdm_validate_string(ctx, value, -1, -1, ProcessSupportedSortingMethods, NULL))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
dmuci_set_value("sysmngr", "process", "sorting_method", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_max_process_entries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
|
||||||
|
{
|
||||||
|
*value = dmuci_get_option_value_fallback_def("sysmngr", "process", "max_process_entries", "-1");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_max_process_entries(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
|
||||||
|
{
|
||||||
|
char buf[16] = {0};
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case VALUECHECK:
|
||||||
|
snprintf(buf, sizeof(buf), "%u", MAX_PROCESS_ENTRIES);
|
||||||
|
|
||||||
|
if (bbfdm_validate_int(ctx, value, RANGE_ARGS{{"-1",buf}}, 1))
|
||||||
|
return FAULT_9007;
|
||||||
|
break;
|
||||||
|
case VALUESET:
|
||||||
|
dmuci_set_value("sysmngr", "process", "max_process_entries", value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* EVENTS
|
* EVENTS
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
|
|
@ -1058,5 +1236,12 @@ DMLEAF tDeviceInfoProcessStatusParams[] = {
|
||||||
{"CPUUsage", &DMREAD, DMT_UNINT, get_process_cpu_usage, NULL, BBFDM_BOTH},
|
{"CPUUsage", &DMREAD, DMT_UNINT, get_process_cpu_usage, NULL, BBFDM_BOTH},
|
||||||
{"ProcessNumberOfEntries", &DMREAD, DMT_UNINT, get_process_number_of_entries, NULL, BBFDM_BOTH},
|
{"ProcessNumberOfEntries", &DMREAD, DMT_UNINT, get_process_number_of_entries, NULL, BBFDM_BOTH},
|
||||||
{"CPUNumberOfEntries", &DMREAD, DMT_UNINT, get_DeviceInfoProcessStatus_CPUNumberOfEntries, NULL, BBFDM_BOTH},
|
{"CPUNumberOfEntries", &DMREAD, DMT_UNINT, get_DeviceInfoProcessStatus_CPUNumberOfEntries, NULL, BBFDM_BOTH},
|
||||||
|
|
||||||
|
#ifdef SYSMNGR_VENDOR_EXTENSIONS
|
||||||
|
{CUSTOM_PREFIX"ProcessSupportedSortingMethods", &DMREAD, DMT_STRING, get_process_supported_sorting_methods, NULL, BBFDM_BOTH},
|
||||||
|
{CUSTOM_PREFIX"ProcessCurrentSortingMethod", &DMWRITE, DMT_STRING, get_process_current_sorting_method, set_process_current_sorting_method, BBFDM_BOTH},
|
||||||
|
{CUSTOM_PREFIX"MaxProcessEntries", &DMWRITE, DMT_INT, get_max_process_entries, set_max_process_entries, BBFDM_BOTH},
|
||||||
|
#endif
|
||||||
|
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ static void config_reload_cb(struct ubus_context *ctx, struct ubus_event_handler
|
||||||
#ifdef SYSMNGR_PROCESS_STATUS
|
#ifdef SYSMNGR_PROCESS_STATUS
|
||||||
sysmngr_cpu_clean();
|
sysmngr_cpu_clean();
|
||||||
sysmngr_cpu_init();
|
sysmngr_cpu_init();
|
||||||
|
|
||||||
|
sysmngr_process_clean(ctx);
|
||||||
|
sysmngr_process_init(ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SYSMNGR_MEMORY_STATUS
|
#ifdef SYSMNGR_MEMORY_STATUS
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue