mirror of
https://dev.iopsys.eu/system/sysmngr.git
synced 2025-12-10 08:14:38 +01:00
Add support to show only top N process
This commit is contained in:
parent
2c842f0875
commit
ea11440212
1 changed files with 80 additions and 43 deletions
123
src/processes.c
123
src/processes.c
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2019-2024 iopsys Software Solutions AB
|
* Copyright (C) 2019-2025 iopsys Software Solutions AB
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Lesser General Public License version 2.1
|
* it under the terms of the GNU Lesser General Public License version 2.1
|
||||||
|
|
@ -46,6 +46,7 @@ typedef struct process_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;
|
||||||
} process_ctx;
|
} process_ctx;
|
||||||
|
|
||||||
typedef struct cpu_info {
|
typedef struct cpu_info {
|
||||||
|
|
@ -204,44 +205,83 @@ static void procps_get_cmdline(char *buf, int bufsz, const char *pid, const char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter function for scandir to select only numeric directories (process IDs)
|
||||||
|
static int filter_process_dirs(const struct dirent *entry)
|
||||||
|
{
|
||||||
|
// Only interested in directories with numeric names
|
||||||
|
if (entry->d_type != DT_DIR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Check if all characters are digits
|
||||||
|
for (const char *p = entry->d_name; *p; p++) {
|
||||||
|
if (!isdigit(*p))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparison function for scandir to sort numerically
|
||||||
|
static int numeric_sort(const struct dirent **a, const struct dirent **b)
|
||||||
|
{
|
||||||
|
long num1 = strtol((*a)->d_name, NULL, 10);
|
||||||
|
long num2 = strtol((*b)->d_name, NULL, 10);
|
||||||
|
return num1 - num2;
|
||||||
|
}
|
||||||
|
|
||||||
static void init_process_list(void)
|
static void init_process_list(void)
|
||||||
{
|
{
|
||||||
struct dirent *entry = NULL;
|
struct dirent **namelist = NULL;
|
||||||
DIR *dir = NULL;
|
int process_num = 0;
|
||||||
|
|
||||||
dir = opendir("/proc");
|
|
||||||
if (dir == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BBFDM_INFO("Init process list");
|
BBFDM_INFO("Init process list");
|
||||||
|
|
||||||
while ((entry = readdir(dir)) != NULL) {
|
// Scan '/proc' for numeric directories
|
||||||
|
int count = scandir("/proc", &namelist, filter_process_dirs, numeric_sort);
|
||||||
|
if (count < 0) {
|
||||||
|
BBFDM_ERR("Error getting process list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BBFDM_DEBUG("Process Number: '%d'", count);
|
||||||
|
|
||||||
|
for (int i = count - 1; i >= 0; i--) {
|
||||||
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;
|
||||||
|
|
||||||
int digit = entry->d_name[0] - '0';
|
// Handle max_entries limits (negative means show all)
|
||||||
if (digit < 0 || digit > 9)
|
if (g_process_ctx.max_entries >= 0 && process_num >= g_process_ctx.max_entries) {
|
||||||
|
FREE(namelist[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(fstat, sizeof(fstat), "/proc/%s/stat", entry->d_name);
|
snprintf(fstat, sizeof(fstat), "/proc/%s/stat", namelist[i]->d_name);
|
||||||
if (stat(fstat, &stats))
|
if (stat(fstat, &stats)) {
|
||||||
|
FREE(namelist[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
n = dm_file_to_buf(fstat, buf, sizeof(buf));
|
n = dm_file_to_buf(fstat, buf, sizeof(buf));
|
||||||
if (n < 0)
|
if (n < 0) {
|
||||||
|
FREE(namelist[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
char *comm2 = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
|
char *comm2 = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */
|
||||||
if (!comm2) /* sanity check */
|
if (!comm2) { /* sanity check */
|
||||||
continue;
|
FREE(namelist[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
comm2[0] = '\0';
|
comm2[0] = '\0';
|
||||||
char *comm1 = strchr(buf, '(');
|
char *comm1 = strchr(buf, '(');
|
||||||
if (!comm1) /* sanity check */
|
if (!comm1) { /* sanity check */
|
||||||
continue;
|
FREE(namelist[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
DM_STRNCPY(comm, comm1 + 1, sizeof(comm));
|
DM_STRNCPY(comm, comm1 + 1, sizeof(comm));
|
||||||
|
|
||||||
|
|
@ -262,10 +302,12 @@ static void init_process_list(void)
|
||||||
&vsize
|
&vsize
|
||||||
);
|
);
|
||||||
|
|
||||||
if (n != 5)
|
if (n != 5) {
|
||||||
|
FREE(namelist[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
procps_get_cmdline(command, sizeof(command), entry->d_name, comm);
|
procps_get_cmdline(command, sizeof(command), namelist[i]->d_name, comm);
|
||||||
|
|
||||||
snprintf(cputime, sizeof(cputime), "%lu", ((stime / sysconf(_SC_CLK_TCK)) + (utime / sysconf(_SC_CLK_TCK))) * 1000);
|
snprintf(cputime, sizeof(cputime), "%lu", ((stime / sysconf(_SC_CLK_TCK)) + (utime / sysconf(_SC_CLK_TCK))) * 1000);
|
||||||
snprintf(bsize, sizeof(bsize), "%lu", vsize >> 10);
|
snprintf(bsize, sizeof(bsize), "%lu", vsize >> 10);
|
||||||
|
|
@ -274,20 +316,25 @@ static void init_process_list(void)
|
||||||
process_entry *pentry = (process_entry *)calloc(1, sizeof(process_entry));
|
process_entry *pentry = (process_entry *)calloc(1, sizeof(process_entry));
|
||||||
if (!pentry) {
|
if (!pentry) {
|
||||||
BBFDM_ERR("failed to allocate memory for process entry");
|
BBFDM_ERR("failed to allocate memory for process entry");
|
||||||
return;
|
FREE(namelist[i]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&pentry->list, &g_process_ctx.list);
|
list_add_tail(&pentry->list, &g_process_ctx.list);
|
||||||
|
|
||||||
DM_STRNCPY(pentry->pid, entry->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));
|
||||||
DM_STRNCPY(pentry->priority, priori, sizeof(pentry->priority));
|
DM_STRNCPY(pentry->priority, priori, sizeof(pentry->priority));
|
||||||
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++;
|
||||||
|
|
||||||
|
FREE(namelist[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
FREE(namelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_process_list(void)
|
static void free_process_list(void)
|
||||||
|
|
@ -302,6 +349,15 @@ static void free_process_list(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_maximum_process_entries(void)
|
||||||
|
{
|
||||||
|
char buf[8] = {0};
|
||||||
|
|
||||||
|
BBFDM_UCI_GET("sysmngr", "process", "max_process_entries", "-1", buf, sizeof(buf));
|
||||||
|
|
||||||
|
return (int)strtol(buf, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
static int get_instance_refresh_interval(void)
|
static int get_instance_refresh_interval(void)
|
||||||
{
|
{
|
||||||
char buf[8] = {0};
|
char buf[8] = {0};
|
||||||
|
|
@ -322,29 +378,9 @@ static void run_refresh_process_list(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ubus_call_complete_cb(struct ubus_request *req, int ret)
|
|
||||||
{
|
|
||||||
BBFDM_DEBUG("'tr069' ubus callback completed");
|
|
||||||
run_refresh_process_list();
|
|
||||||
FREE(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void process_refresh_instance_timer(struct uloop_timeout *timeout)
|
static void process_refresh_instance_timer(struct uloop_timeout *timeout)
|
||||||
{
|
{
|
||||||
struct blob_buf bb = {0};
|
run_refresh_process_list();
|
||||||
|
|
||||||
memset(&bb, 0, sizeof(struct blob_buf));
|
|
||||||
|
|
||||||
blob_buf_init(&bb, 0);
|
|
||||||
int res = bbfdm_ubus_invoke_async(g_process_ctx.ubus_ctx, "tr069", "status", bb.head, NULL, ubus_call_complete_cb);
|
|
||||||
blob_buf_free(&bb);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
BBFDM_DEBUG("Update process list: 'tr069' ubus object not found");
|
|
||||||
run_refresh_process_list();
|
|
||||||
} else {
|
|
||||||
BBFDM_DEBUG("Process list will be updated after 'tr069' ubus session completes");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_cpu_critical_state_event(unsigned int cpu_utilization)
|
static void send_cpu_critical_state_event(unsigned int cpu_utilization)
|
||||||
|
|
@ -545,6 +581,7 @@ 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.refresh_interval = get_instance_refresh_interval();
|
g_process_ctx.refresh_interval = get_instance_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);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue