summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorbernard <[email protected]>2026-08-23 10:13:24 +0800
committerRbb666 <[email protected]>2026-08-30 20:49:24 +0800
commit5dcbc0dec92259ce8ab87a16fce39d9ce5d15ec8 (patch)
tree7fa0ec2186ce1d3f669eff5bd071b2e26853ddd6 /components
parent04b19b35e30308ba5dcbe72919fdf0a97f7ba61f (diff)
[dfs][procfs] Fix Linux-compatible procfs fields
Grow maps without a 256 VMA cap, skip RSS walks for maps, report matching status text, real RSS/statm, MemAvailable after page-pool free pages, load averages plus last PID, cumulative processes, RV32 cpuinfo, and per-character mount escaping.
Diffstat (limited to 'components')
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c4
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c69
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c2
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c42
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_pid.c183
-rw-r--r--components/dfs/dfs_v2/filesystems/procfs/proc_stat.c2
-rw-r--r--components/lwp/lwp_pid.c24
-rw-r--r--components/lwp/lwp_pid.h2
8 files changed, 279 insertions, 49 deletions
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c
index ca3a8dc48a..094fa39e12 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_cpuinfo.c
@@ -76,7 +76,11 @@ static int seq_show(struct dfs_seq_file *seq, void *data)
dfs_seq_printf(seq, "CPU revision\t: %lu\n", (unsigned long)revision);
#elif defined(__riscv)
dfs_seq_puts(seq, "model name\t: RISC-V Generic\n");
+#if defined(__riscv_xlen) && (__riscv_xlen == 32)
+ dfs_seq_puts(seq, "isa\t\t: rv32\n");
+#else
dfs_seq_puts(seq, "isa\t\t: rv64\n");
+#endif
#else
dfs_seq_puts(seq, "model name\t: RT-Thread Generic CPU\n");
#endif
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c
index acb6ee35b5..44e95ff5f1 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_loadavg.c
@@ -19,10 +19,8 @@
#include <dfs_dentry.h>
#ifdef RT_USING_SMART
-#include "lwp_pid.h"
-#ifdef RT_USING_MUSLLIBC
#include "lwp.h"
-#endif
+#include "lwp_pid.h"
#endif
#ifdef RT_USING_SMART
@@ -32,6 +30,18 @@ struct loadavg_count
int runnable;
};
+/* Fixed-point load averages, 11 bits of fraction like Linux FSHIFT. */
+#define PROC_LOAD_FSHIFT 11
+#define PROC_LOAD_FIXED_1 (1UL << PROC_LOAD_FSHIFT)
+#define PROC_LOAD_EXP_1 1884UL /* 1 / exp(5s / 60s) * 2048 */
+#define PROC_LOAD_EXP_5 2014UL /* 1 / exp(5s / 300s) * 2048 */
+#define PROC_LOAD_EXP_15 2037UL /* 1 / exp(5s / 900s) * 2048 */
+
+static unsigned long load_1 = 0;
+static unsigned long load_5 = 0;
+static unsigned long load_15 = 0;
+static rt_tick_t load_last_tick = 0;
+
static int loadavg_count_pid(pid_t pid, void *arg)
{
struct loadavg_count *count = (struct loadavg_count *)arg;
@@ -42,7 +52,6 @@ static int loadavg_count_pid(pid_t pid, void *arg)
return 0;
}
count->total++;
-#ifdef RT_USING_MUSLLIBC
{
rt_list_t *node;
@@ -50,7 +59,9 @@ static int loadavg_count_pid(pid_t pid, void *arg)
while (node != &lwp->t_grp)
{
rt_thread_t thread = rt_list_entry(node, struct rt_thread, sibling);
- if (RT_SCHED_CTX(thread).stat == RT_THREAD_RUNNING)
+ int stat = RT_SCHED_CTX(thread).stat & RT_THREAD_STAT_MASK;
+
+ if (stat == RT_THREAD_RUNNING || stat == RT_THREAD_READY)
{
count->runnable++;
break;
@@ -58,18 +69,62 @@ static int loadavg_count_pid(pid_t pid, void *arg)
node = node->next;
}
}
-#endif
return 0;
}
+
+static void loadavg_fold(unsigned long active)
+{
+ load_1 = load_1 * PROC_LOAD_EXP_1 / PROC_LOAD_FIXED_1 +
+ active * (PROC_LOAD_FIXED_1 - PROC_LOAD_EXP_1) / PROC_LOAD_FIXED_1;
+ load_5 = load_5 * PROC_LOAD_EXP_5 / PROC_LOAD_FIXED_1 +
+ active * (PROC_LOAD_FIXED_1 - PROC_LOAD_EXP_5) / PROC_LOAD_FIXED_1;
+ load_15 = load_15 * PROC_LOAD_EXP_15 / PROC_LOAD_FIXED_1 +
+ active * (PROC_LOAD_FIXED_1 - PROC_LOAD_EXP_15) / PROC_LOAD_FIXED_1;
+}
+
+static void loadavg_update(unsigned long active)
+{
+ rt_tick_t now = rt_tick_get();
+ rt_tick_t period = RT_TICK_PER_SECOND * 5;
+
+ if (load_last_tick == 0)
+ {
+ load_1 = load_5 = load_15 = active;
+ load_last_tick = now;
+ return;
+ }
+
+ while ((rt_tick_t)(now - load_last_tick) >= period)
+ {
+ loadavg_fold(active);
+ load_last_tick += period;
+ }
+}
+
+static void loadavg_print(struct dfs_seq_file *seq, unsigned long load)
+{
+ unsigned long integer = load >> PROC_LOAD_FSHIFT;
+ unsigned long frac = ((load & (PROC_LOAD_FIXED_1 - 1)) * 100) >> PROC_LOAD_FSHIFT;
+
+ dfs_seq_printf(seq, "%lu.%02lu", integer, frac);
+}
#endif
static int single_show(struct dfs_seq_file *seq, void *data)
{
+ RT_UNUSED(data);
#ifdef RT_USING_SMART
struct loadavg_count count = { 0, 0 };
lwp_pid_for_each(loadavg_count_pid, &count);
- dfs_seq_printf(seq, "0.00 0.00 0.00 %d/%d 0\n", count.runnable, count.total);
+ loadavg_update(((unsigned long)count.runnable) << PROC_LOAD_FSHIFT);
+ loadavg_print(seq, load_1);
+ dfs_seq_puts(seq, " ");
+ loadavg_print(seq, load_5);
+ dfs_seq_puts(seq, " ");
+ loadavg_print(seq, load_15);
+ dfs_seq_printf(seq, " %d/%d %d\n", count.runnable, count.total,
+ (int)lwp_pid_get_last());
#else
dfs_seq_puts(seq, "0.00 0.00 0.00 0/0 0\n");
#endif
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c
index b1617f8bfd..1d8048b06b 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_meminfo.c
@@ -35,12 +35,12 @@ static int single_show(struct dfs_seq_file *seq, void *data)
total_freed = total_freed + total - used;
dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemMaxUsed:", (unsigned long)(max_used / 1024));
- dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemAvailable:", (unsigned long)((total - used) / 1024));
rt_page_get_info(&total, &freed);
total_sum = total_sum + total * RT_MM_PAGE_SIZE;
total_freed = total_freed + freed * RT_MM_PAGE_SIZE;
+ dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemAvailable:", (unsigned long)(total_freed / 1024));
dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemTotal:", (unsigned long)(total_sum / 1024));
dfs_seq_printf(seq, "%-16s%8lu kB\n", "MemFree:", (unsigned long)(total_freed / 1024));
dfs_seq_printf(seq, "%-16s%8lu kB\n", "Buffers:", 0UL);
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
index 1bb3b6a6bc..5d2e75f5a1 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_mounts.c
@@ -29,35 +29,43 @@ static void mnt_escape(const char *source, char *target, rt_size_t target_size)
return;
}
- while (*cursor != '\0' && offset + 4 < target_size)
+ while (*cursor != '\0')
{
+ const char *escape = RT_NULL;
+ rt_size_t need = 1;
+
if (*cursor == ' ')
{
- target[offset++] = '\\';
- target[offset++] = '0';
- target[offset++] = '4';
- target[offset++] = '0';
+ escape = "\\040";
+ need = 4;
}
else if (*cursor == '\t')
{
- target[offset++] = '\\';
- target[offset++] = '0';
- target[offset++] = '1';
- target[offset++] = '1';
+ escape = "\\011";
+ need = 4;
}
else if (*cursor == '\n')
{
- target[offset++] = '\\';
- target[offset++] = '0';
- target[offset++] = '1';
- target[offset++] = '2';
+ escape = "\\012";
+ need = 4;
}
else if (*cursor == '\\')
{
- target[offset++] = '\\';
- target[offset++] = '1';
- target[offset++] = '3';
- target[offset++] = '4';
+ escape = "\\134";
+ need = 4;
+ }
+
+ if (offset + need >= target_size)
+ {
+ break;
+ }
+
+ if (escape)
+ {
+ target[offset++] = escape[0];
+ target[offset++] = escape[1];
+ target[offset++] = escape[2];
+ target[offset++] = escape[3];
}
else
{
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
index 9212351ac4..a3b0422c38 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_pid.c
@@ -46,17 +46,76 @@ struct pid_dentry
static char stat_transform(int __stat)
{
- switch (__stat)
+ int stat = __stat & RT_THREAD_STAT_MASK;
+
+ if (stat == RT_THREAD_RUNNING)
+ {
+ return 'R';
+ }
+ if (stat == RT_THREAD_READY)
{
- case RT_THREAD_RUNNING:
return 'R';
+ }
+ if (stat == RT_THREAD_CLOSE)
+ {
+ return 'Z';
+ }
+ if (stat & RT_THREAD_SUSPEND_MASK)
+ {
+ return 'S';
+ }
+ return 'T';
+}
+
+static const char *proc_state_desc(char state)
+{
+ switch (state)
+ {
+ case 'R':
+ return "running";
+ case 'S':
+ return "sleeping";
+ case 'Z':
+ return "zombie";
+ case 'T':
+ return "stopped";
default:
- return 'T';
+ return "unknown";
+ }
+}
+
+static char proc_lwp_state(struct rt_lwp *lwp)
+{
+ rt_list_t *node;
+ char state = 'S';
+
+ if (!lwp || lwp->terminated)
+ {
+ return 'Z';
+ }
+
+ node = lwp->t_grp.next;
+ while (node != &lwp->t_grp)
+ {
+ rt_thread_t thread = rt_list_entry(node, struct rt_thread, sibling);
+ char thread_state = stat_transform(RT_SCHED_CTX(thread).stat);
+
+ if (thread_state == 'R')
+ {
+ return 'R';
+ }
+ if (thread_state == 'T')
+ {
+ state = 'T';
+ }
+ node = node->next;
}
+
+ return state;
}
#ifdef ARCH_MM_MMU
-#define PROC_MAP_MAX 256
+#define PROC_MAP_GROW 32
struct proc_map_entry
{
@@ -75,6 +134,8 @@ struct proc_map_context
struct rt_lwp *lwp;
struct proc_map_entry *entries;
rt_size_t count;
+ rt_size_t capacity;
+ rt_bool_t count_resident;
rt_bool_t smaps;
};
@@ -104,17 +165,68 @@ static void proc_map_name(rt_varea_t varea, struct proc_map_entry *entry)
entry->name[sizeof(entry->name) - 1] = '\0';
}
+static int proc_map_grow(struct proc_map_context *context)
+{
+ struct proc_map_entry *entries;
+ rt_size_t capacity;
+
+ if (context->count < context->capacity)
+ {
+ return 0;
+ }
+
+ capacity = context->capacity ? context->capacity * 2 : PROC_MAP_GROW;
+ entries = rt_realloc(context->entries, capacity * sizeof(*entries));
+ if (!entries)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_memset(entries + context->capacity, 0,
+ (capacity - context->capacity) * sizeof(*entries));
+ context->entries = entries;
+ context->capacity = capacity;
+ return 0;
+}
+
+static rt_size_t proc_map_count_resident(rt_varea_t varea)
+{
+ uintptr_t address;
+ uintptr_t end;
+ rt_size_t resident_pages = 0;
+
+ if (!varea || varea->size == 0)
+ {
+ return 0;
+ }
+
+ address = (uintptr_t)varea->start;
+ end = address + varea->size;
+ while (address < end)
+ {
+ if (rt_hw_mmu_v2p(varea->aspace, (void *)address) != ARCH_MAP_FAILED)
+ {
+ resident_pages++;
+ }
+ address += ARCH_PAGE_SIZE;
+ }
+
+ return resident_pages;
+}
+
static int proc_map_collect(rt_varea_t varea, void *arg)
{
struct proc_map_context *context = (struct proc_map_context *)arg;
struct proc_map_entry *entry;
- uintptr_t address;
- uintptr_t end;
- if (context->count >= PROC_MAP_MAX || !varea || varea->size == 0)
+ if (!varea || varea->size == 0)
{
return 0;
}
+ if (proc_map_grow(context) != 0)
+ {
+ return -RT_ENOMEM;
+ }
entry = &context->entries[context->count++];
entry->start = (uintptr_t)varea->start;
@@ -124,20 +236,36 @@ static int proc_map_collect(rt_varea_t varea, void *arg)
proc_map_permissions(varea, entry);
proc_map_name(varea, entry);
- address = entry->start;
- end = entry->end;
- while (address < end)
+ if (context->count_resident)
{
- if (rt_hw_mmu_v2p(varea->aspace, (void *)address) != ARCH_MAP_FAILED)
- {
- entry->resident_pages++;
- }
- address += ARCH_PAGE_SIZE;
+ entry->resident_pages = proc_map_count_resident(varea);
}
return 0;
}
+static rt_size_t proc_lwp_resident_pages(struct rt_lwp *lwp)
+{
+ rt_varea_t varea;
+ rt_size_t resident_pages = 0;
+
+ if (!lwp || !lwp->aspace)
+ {
+ return 0;
+ }
+
+ RD_LOCK(lwp->aspace);
+ varea = ASPACE_VAREA_FIRST(lwp->aspace);
+ while (varea)
+ {
+ resident_pages += proc_map_count_resident(varea);
+ varea = ASPACE_VAREA_NEXT(varea);
+ }
+ RD_UNLOCK(lwp->aspace);
+
+ return resident_pages;
+}
+
static void proc_map_context_free(struct proc_map_context *context)
{
if (context)
@@ -244,7 +372,9 @@ static int proc_maps_open(struct dfs_file *file)
return -RT_ENOENT;
}
context->smaps = !rt_strcmp(dentry->name, "smaps");
- context->entries = rt_calloc(PROC_MAP_MAX, sizeof(*context->entries));
+ context->count_resident = context->smaps;
+ context->capacity = PROC_MAP_GROW;
+ context->entries = rt_calloc(context->capacity, sizeof(*context->entries));
if (!context->entries)
{
proc_map_context_free(context);
@@ -255,7 +385,12 @@ static int proc_maps_open(struct dfs_file *file)
varea = ASPACE_VAREA_FIRST(context->lwp->aspace);
while (varea)
{
- proc_map_collect(varea, context);
+ if (proc_map_collect(varea, context) != 0)
+ {
+ RD_UNLOCK(context->lwp->aspace);
+ proc_map_context_free(context);
+ return -RT_ENOMEM;
+ }
varea = ASPACE_VAREA_NEXT(varea);
}
RD_UNLOCK(context->lwp->aspace);
@@ -447,6 +582,7 @@ static int proc_pid_status_show(struct dfs_seq_file *seq, void *data)
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
struct rt_lwp *lwp = lwp_from_pid_and_lock(dentry->pid);
rt_size_t vm_size = 0;
+ rt_size_t vm_rss = 0;
rt_size_t thread_count = 0;
rt_list_t *node;
char state;
@@ -461,6 +597,7 @@ static int proc_pid_status_show(struct dfs_seq_file *seq, void *data)
if (lwp->aspace)
{
vm_size = rt_aspace_count_vsz(lwp->aspace);
+ vm_rss = proc_lwp_resident_pages(lwp) * ARCH_PAGE_SIZE;
}
#endif
node = lwp->t_grp.next;
@@ -469,15 +606,15 @@ static int proc_pid_status_show(struct dfs_seq_file *seq, void *data)
thread_count++;
node = node->next;
}
- state = lwp->terminated ? 'Z' : 'S';
+ state = proc_lwp_state(lwp);
dfs_seq_printf(seq, "Name:\t%s\n", lwp->cmd);
- dfs_seq_printf(seq, "State:\t%c (sleeping)\n", state);
+ dfs_seq_printf(seq, "State:\t%c (%s)\n", state, proc_state_desc(state));
dfs_seq_printf(seq, "Pid:\t%d\n", lwp->pid);
dfs_seq_printf(seq, "PPid:\t%d\n", lwp->parent ? lwp->parent->pid : 0);
dfs_seq_puts(seq, "Uid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\n");
dfs_seq_printf(seq, "Threads:\t%lu\n", (unsigned long)thread_count);
dfs_seq_printf(seq, "VmSize:\t%lu kB\n", (unsigned long)(vm_size / 1024));
- dfs_seq_printf(seq, "VmRSS:\t%lu kB\n", (unsigned long)(vm_size / 1024));
+ dfs_seq_printf(seq, "VmRSS:\t%lu kB\n", (unsigned long)(vm_rss / 1024));
dfs_seq_puts(seq, "VmData:\t0 kB\nVmStk:\t0 kB\nVmExe:\t0 kB\nVmLib:\t0 kB\n");
lwp_from_pid_release_lock(lwp);
return 0;
@@ -488,6 +625,7 @@ static int proc_pid_statm_show(struct dfs_seq_file *seq, void *data)
struct proc_dentry *dentry = (struct proc_dentry *)seq->file->vnode->data;
struct rt_lwp *lwp = lwp_from_pid_and_lock(dentry->pid);
rt_size_t size_pages = 0;
+ rt_size_t resident_pages = 0;
rt_size_t text_pages = 0;
rt_size_t data_pages = 0;
@@ -501,14 +639,13 @@ static int proc_pid_statm_show(struct dfs_seq_file *seq, void *data)
if (lwp->aspace)
{
size_pages = (rt_aspace_count_vsz(lwp->aspace) + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE;
+ resident_pages = proc_lwp_resident_pages(lwp);
}
-#endif
-#ifdef ARCH_MM_MMU
text_pages = (lwp->text_size + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE;
data_pages = (lwp->data_size + ARCH_PAGE_SIZE - 1) / ARCH_PAGE_SIZE;
#endif
dfs_seq_printf(seq, "%lu %lu 0 %lu 0 %lu 0\n",
- (unsigned long)size_pages, (unsigned long)size_pages,
+ (unsigned long)size_pages, (unsigned long)resident_pages,
(unsigned long)text_pages, (unsigned long)data_pages);
lwp_from_pid_release_lock(lwp);
return 0;
diff --git a/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
index c24adb291e..9b8a6a80c9 100644
--- a/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
+++ b/components/dfs/dfs_v2/filesystems/procfs/proc_stat.c
@@ -118,7 +118,7 @@ static int seq_show(struct dfs_seq_file *seq, void *data)
{
struct stat_process_count process_count = { 0, 0 };
lwp_pid_for_each(stat_process_count, &process_count);
- dfs_seq_printf(seq, "processes %d\n", process_count.total);
+ dfs_seq_printf(seq, "processes %lu\n", lwp_pid_get_create_count());
dfs_seq_printf(seq, "procs_running %d\n", process_count.running);
dfs_seq_puts(seq, "procs_blocked 0\n");
}
diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c
index 12a4dde86f..1f0e09ae9c 100644
--- a/components/lwp/lwp_pid.c
+++ b/components/lwp/lwp_pid.c
@@ -68,6 +68,7 @@ static struct lwp_avl_struct *lwp_pid_free_head = RT_NULL;
static int lwp_pid_ary_alloced = 0;
static struct lwp_avl_struct *lwp_pid_root = RT_NULL;
static pid_t current_pid = 0;
+static unsigned long lwp_create_count = 0;
static struct rt_mutex pid_mtx;
static struct rt_wqueue _pid_emptyq;
@@ -166,6 +167,28 @@ static int _before_cb(struct lwp_avl_struct *node, void *data)
return param->cb(pid, param->data);
}
+unsigned long lwp_pid_get_create_count(void)
+{
+ unsigned long count;
+
+ lwp_pid_lock_take();
+ count = lwp_create_count;
+ lwp_pid_lock_release();
+
+ return count;
+}
+
+pid_t lwp_pid_get_last(void)
+{
+ pid_t pid;
+
+ lwp_pid_lock_take();
+ pid = current_pid;
+ lwp_pid_lock_release();
+
+ return pid;
+}
+
/**
* @brief Iterate over all process IDs
*
@@ -694,6 +717,7 @@ rt_lwp_t lwp_create(rt_base_t flags)
{
new_lwp->pid = pid;
lwp_pid_set_lwp_locked(pid, new_lwp);
+ lwp_create_count++;
}
lwp_pid_lock_release();
}
diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h
index 5b85b32197..a295137fbc 100644
--- a/components/lwp/lwp_pid.h
+++ b/components/lwp/lwp_pid.h
@@ -28,6 +28,8 @@ struct lwp_avl_struct *lwp_get_pid_ary(void);
int lwp_pid_init(void);
int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to);
int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data);
+unsigned long lwp_pid_get_create_count(void);
+pid_t lwp_pid_get_last(void);
void lwp_pid_put(struct rt_lwp *lwp);
void lwp_pid_rollback(struct rt_lwp *lwp);
void lwp_pid_lock_take(void);