procstat&sysstat

This commit is contained in:
2026-04-17 21:14:40 +08:00
parent d4c2c62543
commit 081b0d391a
10 changed files with 726 additions and 4 deletions

View File

@@ -385,6 +385,7 @@ set(RAMDISK_ROOT_APPS)
set(USER_SHELL_COMMAND_APPS
help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
bg fg jobs kill ps top
procstat sysstat
shutdown restart exit clear ansi ansitest wavplay fastfetch memstat fsstat taskstat userstat
shstat stats tty dmesg kbdstat mkdir touch write append cp mv rm kdbg
)

View File

@@ -30,7 +30,8 @@ static int ush_cmd_help(void) {
ush_writeln(" spawn <path|name> [args...] / bg <path|name> [args...]");
ush_writeln(" wait <pid> / fg [pid]");
ush_writeln(" kill <pid> [signal]");
ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]");
ush_writeln(" jobs [-a] / ps [-a] [-u] / procstat [pid|self] [-a]");
ush_writeln(" top [--once] [-n loops] [-d ticks] / sysstat [-a] [-n N]");
ush_writeln(" kdbg sym <addr> / kdbg bt <rbp> <rip> / kdbg regs");
ush_writeln(" sleep <ticks>");
ush_writeln(" spin (busy loop test for Alt+Ctrl+C)");

View File

@@ -0,0 +1,244 @@
#include "cmd_runtime.h"
static const char *ush_procstat_state_name(u64 state) {
if (state == CLEONOS_PROC_STATE_PENDING) {
return "PEND";
}
if (state == CLEONOS_PROC_STATE_RUNNING) {
return "RUN ";
}
if (state == CLEONOS_PROC_STATE_STOPPED) {
return "STOP";
}
if (state == CLEONOS_PROC_STATE_EXITED) {
return "EXIT";
}
return "UNKN";
}
static int ush_procstat_next_token(const char **io_cursor, char *out, u64 out_size) {
const char *p;
u64 n = 0ULL;
if (io_cursor == (const char **)0 || out == (char *)0 || out_size == 0ULL) {
return 0;
}
out[0] = '\0';
p = *io_cursor;
if (p == (const char *)0) {
return 0;
}
while (*p != '\0' && ush_is_space(*p) != 0) {
p++;
}
if (*p == '\0') {
*io_cursor = p;
return 0;
}
while (*p != '\0' && ush_is_space(*p) == 0) {
if (n + 1ULL < out_size) {
out[n++] = *p;
}
p++;
}
out[n] = '\0';
*io_cursor = p;
return 1;
}
static void ush_procstat_print_line(const cleonos_proc_snapshot *snap) {
if (snap == (const cleonos_proc_snapshot *)0) {
return;
}
ush_write("PID=");
ush_write_hex_u64(snap->pid);
ush_write(" ST=");
ush_write(ush_procstat_state_name(snap->state));
ush_write(" TTY=");
ush_write_hex_u64(snap->tty_index);
ush_write(" RT=");
ush_write_hex_u64(snap->runtime_ticks);
ush_write(" MEM=");
ush_write_hex_u64(snap->mem_bytes);
ush_write(" SIG=");
ush_write_hex_u64(snap->last_signal);
ush_write(" PATH=");
ush_writeln(snap->path);
}
static void ush_procstat_print_detail(const cleonos_proc_snapshot *snap) {
if (snap == (const cleonos_proc_snapshot *)0) {
return;
}
ush_writeln("procstat:");
ush_print_kv_hex(" PID", snap->pid);
ush_print_kv_hex(" PPID", snap->ppid);
ush_write(" STATE: ");
ush_write(ush_procstat_state_name(snap->state));
ush_write_char('\n');
ush_print_kv_hex(" STATE_ID", snap->state);
ush_print_kv_hex(" TTY", snap->tty_index);
ush_print_kv_hex(" STARTED_TICK", snap->started_tick);
ush_print_kv_hex(" EXITED_TICK", snap->exited_tick);
ush_print_kv_hex(" RUNTIME_TICKS", snap->runtime_ticks);
ush_print_kv_hex(" MEM_BYTES", snap->mem_bytes);
ush_print_kv_hex(" EXIT_STATUS", snap->exit_status);
ush_print_kv_hex(" LAST_SIGNAL", snap->last_signal);
ush_print_kv_hex(" LAST_FAULT_VECTOR", snap->last_fault_vector);
ush_print_kv_hex(" LAST_FAULT_ERROR", snap->last_fault_error);
ush_print_kv_hex(" LAST_FAULT_RIP", snap->last_fault_rip);
ush_write(" PATH: ");
ush_writeln(snap->path);
}
static int ush_procstat_parse_args(const char *arg, u64 *out_pid, int *out_has_pid, int *out_include_exited) {
const char *cursor = arg;
char token[USH_PATH_MAX];
u64 parsed_pid = 0ULL;
int has_pid = 0;
int include_exited = 0;
if (out_pid == (u64 *)0 || out_has_pid == (int *)0 || out_include_exited == (int *)0) {
return 0;
}
while (ush_procstat_next_token(&cursor, token, (u64)sizeof(token)) != 0) {
if (ush_streq(token, "-a") != 0 || ush_streq(token, "--all") != 0) {
include_exited = 1;
continue;
}
if (ush_streq(token, "self") != 0) {
if (has_pid != 0) {
return 0;
}
parsed_pid = cleonos_sys_getpid();
has_pid = 1;
continue;
}
if (ush_parse_u64_dec(token, &parsed_pid) != 0 && parsed_pid != 0ULL) {
if (has_pid != 0) {
return 0;
}
has_pid = 1;
continue;
}
return 0;
}
*out_pid = parsed_pid;
*out_has_pid = has_pid;
*out_include_exited = include_exited;
return 1;
}
static int ush_cmd_procstat(const char *arg) {
u64 target_pid = 0ULL;
int has_pid = 0;
int include_exited = 0;
if (ush_procstat_parse_args(arg, &target_pid, &has_pid, &include_exited) == 0) {
ush_writeln("procstat: usage procstat [pid|self] [-a|--all]");
return 0;
}
if (has_pid != 0) {
cleonos_proc_snapshot snap;
if (cleonos_sys_proc_snapshot(target_pid, &snap, (u64)sizeof(snap)) == 0ULL) {
ush_writeln("procstat: pid not found");
return 0;
}
ush_procstat_print_detail(&snap);
return 1;
}
{
u64 proc_count = cleonos_sys_proc_count();
u64 i;
u64 shown = 0ULL;
ush_writeln("procstat:");
for (i = 0ULL; i < proc_count; i++) {
u64 pid = 0ULL;
cleonos_proc_snapshot snap;
if (cleonos_sys_proc_pid_at(i, &pid) == 0ULL || pid == 0ULL) {
continue;
}
if (cleonos_sys_proc_snapshot(pid, &snap, (u64)sizeof(snap)) == 0ULL) {
continue;
}
if (include_exited == 0 && snap.state == CLEONOS_PROC_STATE_EXITED) {
continue;
}
ush_procstat_print_line(&snap);
shown++;
}
if (shown == 0ULL) {
ush_writeln("(no process)");
}
}
return 1;
}
int cleonos_app_main(void) {
ush_cmd_ctx ctx;
ush_cmd_ret ret;
ush_state sh;
char initial_cwd[USH_PATH_MAX];
int has_context = 0;
int success = 0;
const char *arg = "";
ush_zero(&ctx, (u64)sizeof(ctx));
ush_zero(&ret, (u64)sizeof(ret));
ush_init_state(&sh);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
if (ush_command_ctx_read(&ctx) != 0) {
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "procstat") != 0) {
has_context = 1;
arg = ctx.arg;
if (ctx.cwd[0] == '/') {
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
}
}
}
success = ush_cmd_procstat(arg);
if (has_context != 0) {
if (ush_streq(sh.cwd, initial_cwd) == 0) {
ret.flags |= USH_CMD_RET_FLAG_CWD;
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
}
if (sh.exit_requested != 0) {
ret.flags |= USH_CMD_RET_FLAG_EXIT;
ret.exit_code = sh.exit_code;
}
(void)ush_command_ret_write(&ret);
}
return (success != 0) ? 0 : 1;
}

View File

@@ -155,7 +155,8 @@ static int ush_cmd_help(void) {
ush_writeln(" spawn <path|name> [args...] / bg <path|name> [args...]");
ush_writeln(" wait <pid> / fg [pid]");
ush_writeln(" kill <pid> [signal]");
ush_writeln(" jobs [-a] / ps [-a] [-u] / top [--once] [-n loops] [-d ticks]");
ush_writeln(" jobs [-a] / ps [-a] [-u] / procstat [pid|self] [-a]");
ush_writeln(" top [--once] [-n loops] [-d ticks] / sysstat [-a] [-n N]");
ush_writeln(" kdbg sym <addr> / kdbg bt <rbp> <rip> / kdbg regs");
ush_writeln(" sleep <ticks>");
ush_writeln(" yield");

View File

@@ -0,0 +1,311 @@
#include "cmd_runtime.h"
#define USH_SYSSTAT_MAX_IDS (CLEONOS_SYSCALL_STATS_RECENT_ID + 1ULL)
#define USH_SYSSTAT_DEFAULT_TOP 12ULL
typedef struct ush_sysstat_entry {
u64 id;
u64 recent;
u64 total;
const char *name;
} ush_sysstat_entry;
static const char *ush_sysstat_name_for_id(u64 id) {
switch (id) {
case CLEONOS_SYSCALL_LOG_WRITE: return "LOG_WRITE";
case CLEONOS_SYSCALL_TIMER_TICKS: return "TIMER_TICKS";
case CLEONOS_SYSCALL_TASK_COUNT: return "TASK_COUNT";
case CLEONOS_SYSCALL_CUR_TASK: return "CUR_TASK";
case CLEONOS_SYSCALL_SERVICE_COUNT: return "SERVICE_COUNT";
case CLEONOS_SYSCALL_SERVICE_READY_COUNT: return "SERVICE_READY";
case CLEONOS_SYSCALL_CONTEXT_SWITCHES: return "CONTEXT_SWITCH";
case CLEONOS_SYSCALL_KELF_COUNT: return "KELF_COUNT";
case CLEONOS_SYSCALL_KELF_RUNS: return "KELF_RUNS";
case CLEONOS_SYSCALL_FS_NODE_COUNT: return "FS_NODE_COUNT";
case CLEONOS_SYSCALL_FS_CHILD_COUNT: return "FS_CHILD_COUNT";
case CLEONOS_SYSCALL_FS_GET_CHILD_NAME: return "FS_CHILD_NAME";
case CLEONOS_SYSCALL_FS_READ: return "FS_READ";
case CLEONOS_SYSCALL_EXEC_PATH: return "EXEC_PATH";
case CLEONOS_SYSCALL_EXEC_REQUESTS: return "EXEC_REQUESTS";
case CLEONOS_SYSCALL_EXEC_SUCCESS: return "EXEC_SUCCESS";
case CLEONOS_SYSCALL_USER_SHELL_READY: return "USER_SHELL_READY";
case CLEONOS_SYSCALL_USER_EXEC_REQUESTED: return "USER_EXEC_REQ";
case CLEONOS_SYSCALL_USER_LAUNCH_TRIES: return "USER_LAUNCH_TRY";
case CLEONOS_SYSCALL_USER_LAUNCH_OK: return "USER_LAUNCH_OK";
case CLEONOS_SYSCALL_USER_LAUNCH_FAIL: return "USER_LAUNCH_FAIL";
case CLEONOS_SYSCALL_TTY_COUNT: return "TTY_COUNT";
case CLEONOS_SYSCALL_TTY_ACTIVE: return "TTY_ACTIVE";
case CLEONOS_SYSCALL_TTY_SWITCH: return "TTY_SWITCH";
case CLEONOS_SYSCALL_TTY_WRITE: return "TTY_WRITE";
case CLEONOS_SYSCALL_TTY_WRITE_CHAR: return "TTY_WRITE_CHAR";
case CLEONOS_SYSCALL_KBD_GET_CHAR: return "KBD_GET_CHAR";
case CLEONOS_SYSCALL_FS_STAT_TYPE: return "FS_STAT_TYPE";
case CLEONOS_SYSCALL_FS_STAT_SIZE: return "FS_STAT_SIZE";
case CLEONOS_SYSCALL_FS_MKDIR: return "FS_MKDIR";
case CLEONOS_SYSCALL_FS_WRITE: return "FS_WRITE";
case CLEONOS_SYSCALL_FS_APPEND: return "FS_APPEND";
case CLEONOS_SYSCALL_FS_REMOVE: return "FS_REMOVE";
case CLEONOS_SYSCALL_LOG_JOURNAL_COUNT: return "LOG_JCOUNT";
case CLEONOS_SYSCALL_LOG_JOURNAL_READ: return "LOG_JREAD";
case CLEONOS_SYSCALL_KBD_BUFFERED: return "KBD_BUFFERED";
case CLEONOS_SYSCALL_KBD_PUSHED: return "KBD_PUSHED";
case CLEONOS_SYSCALL_KBD_POPPED: return "KBD_POPPED";
case CLEONOS_SYSCALL_KBD_DROPPED: return "KBD_DROPPED";
case CLEONOS_SYSCALL_KBD_HOTKEY_SWITCHES: return "KBD_HOTKEYS";
case CLEONOS_SYSCALL_GETPID: return "GETPID";
case CLEONOS_SYSCALL_SPAWN_PATH: return "SPAWN_PATH";
case CLEONOS_SYSCALL_WAITPID: return "WAITPID";
case CLEONOS_SYSCALL_EXIT: return "EXIT";
case CLEONOS_SYSCALL_SLEEP_TICKS: return "SLEEP_TICKS";
case CLEONOS_SYSCALL_YIELD: return "YIELD";
case CLEONOS_SYSCALL_SHUTDOWN: return "SHUTDOWN";
case CLEONOS_SYSCALL_RESTART: return "RESTART";
case CLEONOS_SYSCALL_AUDIO_AVAILABLE: return "AUDIO_AVAIL";
case CLEONOS_SYSCALL_AUDIO_PLAY_TONE: return "AUDIO_TONE";
case CLEONOS_SYSCALL_AUDIO_STOP: return "AUDIO_STOP";
case CLEONOS_SYSCALL_EXEC_PATHV: return "EXEC_PATHV";
case CLEONOS_SYSCALL_SPAWN_PATHV: return "SPAWN_PATHV";
case CLEONOS_SYSCALL_PROC_ARGC: return "PROC_ARGC";
case CLEONOS_SYSCALL_PROC_ARGV: return "PROC_ARGV";
case CLEONOS_SYSCALL_PROC_ENVC: return "PROC_ENVC";
case CLEONOS_SYSCALL_PROC_ENV: return "PROC_ENV";
case CLEONOS_SYSCALL_PROC_LAST_SIGNAL: return "PROC_LAST_SIG";
case CLEONOS_SYSCALL_PROC_FAULT_VECTOR: return "PROC_FAULT_VEC";
case CLEONOS_SYSCALL_PROC_FAULT_ERROR: return "PROC_FAULT_ERR";
case CLEONOS_SYSCALL_PROC_FAULT_RIP: return "PROC_FAULT_RIP";
case CLEONOS_SYSCALL_PROC_COUNT: return "PROC_COUNT";
case CLEONOS_SYSCALL_PROC_PID_AT: return "PROC_PID_AT";
case CLEONOS_SYSCALL_PROC_SNAPSHOT: return "PROC_SNAPSHOT";
case CLEONOS_SYSCALL_PROC_KILL: return "PROC_KILL";
case CLEONOS_SYSCALL_KDBG_SYM: return "KDBG_SYM";
case CLEONOS_SYSCALL_KDBG_BT: return "KDBG_BT";
case CLEONOS_SYSCALL_KDBG_REGS: return "KDBG_REGS";
case CLEONOS_SYSCALL_STATS_TOTAL: return "STATS_TOTAL";
case CLEONOS_SYSCALL_STATS_ID_COUNT: return "STATS_ID_COUNT";
case CLEONOS_SYSCALL_STATS_RECENT_WINDOW: return "STATS_RECENT_WIN";
case CLEONOS_SYSCALL_STATS_RECENT_ID: return "STATS_RECENT_ID";
default: return "UNKNOWN";
}
}
static int ush_sysstat_next_token(const char **io_cursor, char *out, u64 out_size) {
const char *p;
u64 n = 0ULL;
if (io_cursor == (const char **)0 || out == (char *)0 || out_size == 0ULL) {
return 0;
}
out[0] = '\0';
p = *io_cursor;
if (p == (const char *)0) {
return 0;
}
while (*p != '\0' && ush_is_space(*p) != 0) {
p++;
}
if (*p == '\0') {
*io_cursor = p;
return 0;
}
while (*p != '\0' && ush_is_space(*p) == 0) {
if (n + 1ULL < out_size) {
out[n++] = *p;
}
p++;
}
out[n] = '\0';
*io_cursor = p;
return 1;
}
static int ush_sysstat_parse_args(const char *arg, int *out_show_all, u64 *out_limit) {
const char *cursor = arg;
char token[USH_PATH_MAX];
int show_all = 0;
u64 limit = USH_SYSSTAT_DEFAULT_TOP;
if (out_show_all == (int *)0 || out_limit == (u64 *)0) {
return 0;
}
while (ush_sysstat_next_token(&cursor, token, (u64)sizeof(token)) != 0) {
if (ush_streq(token, "-a") != 0 || ush_streq(token, "--all") != 0) {
show_all = 1;
continue;
}
if (ush_streq(token, "-n") != 0 || ush_streq(token, "--top") != 0) {
if (ush_sysstat_next_token(&cursor, token, (u64)sizeof(token)) == 0 || ush_parse_u64_dec(token, &limit) == 0) {
return 0;
}
continue;
}
return 0;
}
if (limit == 0ULL) {
limit = 1ULL;
}
*out_show_all = show_all;
*out_limit = limit;
return 1;
}
static void ush_sysstat_sort_recent(ush_sysstat_entry *entries, u64 count) {
u64 i;
if (entries == (ush_sysstat_entry *)0) {
return;
}
for (i = 0ULL; i + 1ULL < count; i++) {
u64 j;
for (j = i + 1ULL; j < count; j++) {
int swap = 0;
if (entries[j].recent > entries[i].recent) {
swap = 1;
} else if (entries[j].recent == entries[i].recent && entries[j].total > entries[i].total) {
swap = 1;
} else if (entries[j].recent == entries[i].recent && entries[j].total == entries[i].total &&
entries[j].id < entries[i].id) {
swap = 1;
}
if (swap != 0) {
ush_sysstat_entry tmp = entries[i];
entries[i] = entries[j];
entries[j] = tmp;
}
}
}
}
static int ush_cmd_sysstat(const char *arg) {
int show_all = 0;
u64 limit = USH_SYSSTAT_DEFAULT_TOP;
ush_sysstat_entry entries[USH_SYSSTAT_MAX_IDS];
u64 entry_count = 0ULL;
u64 id;
u64 total = cleonos_sys_stats_total();
u64 recent_window = cleonos_sys_stats_recent_window();
u64 to_show;
if (ush_sysstat_parse_args(arg, &show_all, &limit) == 0) {
ush_writeln("sysstat: usage sysstat [-a|--all] [-n N]");
return 0;
}
ush_writeln("sysstat:");
ush_print_kv_hex(" TIMER_TICKS", cleonos_sys_timer_ticks());
ush_print_kv_hex(" TASK_COUNT", cleonos_sys_task_count());
ush_print_kv_hex(" CURRENT_TASK", cleonos_syscall(CLEONOS_SYSCALL_CUR_TASK, 0ULL, 0ULL, 0ULL));
ush_print_kv_hex(" CONTEXT_SWITCHES", cleonos_sys_context_switches());
ush_print_kv_hex(" PROC_COUNT", cleonos_sys_proc_count());
ush_print_kv_hex(" EXEC_REQUESTS", cleonos_sys_exec_request_count());
ush_print_kv_hex(" EXEC_SUCCESS", cleonos_sys_exec_success_count());
ush_print_kv_hex(" SYSCALL_TOTAL", total);
ush_print_kv_hex(" SYSCALL_RECENT_WINDOW", recent_window);
ush_writeln("");
for (id = 0ULL; id < USH_SYSSTAT_MAX_IDS; id++) {
u64 id_total = cleonos_sys_stats_id_count(id);
u64 id_recent = cleonos_sys_stats_recent_id(id);
if (show_all == 0 && id_total == 0ULL && id_recent == 0ULL) {
continue;
}
entries[entry_count].id = id;
entries[entry_count].recent = id_recent;
entries[entry_count].total = id_total;
entries[entry_count].name = ush_sysstat_name_for_id(id);
entry_count++;
}
if (entry_count == 0ULL) {
ush_writeln("(no syscall activity yet)");
return 1;
}
if (show_all == 0) {
ush_sysstat_sort_recent(entries, entry_count);
}
to_show = entry_count;
if (show_all == 0 && to_show > limit) {
to_show = limit;
}
for (id = 0ULL; id < to_show; id++) {
ush_write("ID=");
ush_write_hex_u64(entries[id].id);
ush_write(" RECENT=");
ush_write_hex_u64(entries[id].recent);
ush_write(" TOTAL=");
ush_write_hex_u64(entries[id].total);
ush_write(" NAME=");
ush_writeln(entries[id].name);
}
if (show_all == 0 && entry_count > to_show) {
ush_write("... truncated, use ");
ush_write("sysstat -a");
ush_writeln(" to show all syscall IDs");
}
return 1;
}
int cleonos_app_main(void) {
ush_cmd_ctx ctx;
ush_cmd_ret ret;
ush_state sh;
char initial_cwd[USH_PATH_MAX];
int has_context = 0;
int success = 0;
const char *arg = "";
ush_zero(&ctx, (u64)sizeof(ctx));
ush_zero(&ret, (u64)sizeof(ret));
ush_init_state(&sh);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
if (ush_command_ctx_read(&ctx) != 0) {
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "sysstat") != 0) {
has_context = 1;
arg = ctx.arg;
if (ctx.cwd[0] == '/') {
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
}
}
}
success = ush_cmd_sysstat(arg);
if (has_context != 0) {
if (ush_streq(sh.cwd, initial_cwd) == 0) {
ret.flags |= USH_CMD_RET_FLAG_CWD;
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
}
if (sh.exit_requested != 0) {
ret.flags |= USH_CMD_RET_FLAG_EXIT;
ret.exit_code = sh.exit_code;
}
(void)ush_command_ret_write(&ret);
}
return (success != 0) ? 0 : 1;
}

View File

@@ -103,6 +103,10 @@ typedef struct cleonos_proc_snapshot {
#define CLEONOS_SYSCALL_KDBG_SYM 65ULL
#define CLEONOS_SYSCALL_KDBG_BT 66ULL
#define CLEONOS_SYSCALL_KDBG_REGS 67ULL
#define CLEONOS_SYSCALL_STATS_TOTAL 68ULL
#define CLEONOS_SYSCALL_STATS_ID_COUNT 69ULL
#define CLEONOS_SYSCALL_STATS_RECENT_WINDOW 70ULL
#define CLEONOS_SYSCALL_STATS_RECENT_ID 71ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length);
@@ -172,5 +176,9 @@ u64 cleonos_sys_proc_kill(u64 pid, u64 signal);
u64 cleonos_sys_kdbg_sym(u64 addr, char *out_line, u64 out_size);
u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size);
u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size);
u64 cleonos_sys_stats_total(void);
u64 cleonos_sys_stats_id_count(u64 id);
u64 cleonos_sys_stats_recent_window(void);
u64 cleonos_sys_stats_recent_id(u64 id);
#endif

View File

@@ -294,3 +294,19 @@ u64 cleonos_sys_kdbg_bt(u64 rbp, u64 rip, char *out_text, u64 out_size) {
u64 cleonos_sys_kdbg_regs(char *out_text, u64 out_size) {
return cleonos_syscall(CLEONOS_SYSCALL_KDBG_REGS, (u64)out_text, out_size, 0ULL);
}
u64 cleonos_sys_stats_total(void) {
return cleonos_syscall(CLEONOS_SYSCALL_STATS_TOTAL, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_stats_id_count(u64 id) {
return cleonos_syscall(CLEONOS_SYSCALL_STATS_ID_COUNT, id, 0ULL, 0ULL);
}
u64 cleonos_sys_stats_recent_window(void) {
return cleonos_syscall(CLEONOS_SYSCALL_STATS_RECENT_WINDOW, 0ULL, 0ULL, 0ULL);
}
u64 cleonos_sys_stats_recent_id(u64 id) {
return cleonos_syscall(CLEONOS_SYSCALL_STATS_RECENT_ID, id, 0ULL, 0ULL);
}

View File

@@ -71,6 +71,10 @@
#define CLKS_SYSCALL_KDBG_SYM 65ULL
#define CLKS_SYSCALL_KDBG_BT 66ULL
#define CLKS_SYSCALL_KDBG_REGS 67ULL
#define CLKS_SYSCALL_STATS_TOTAL 68ULL
#define CLKS_SYSCALL_STATS_ID_COUNT 69ULL
#define CLKS_SYSCALL_STATS_RECENT_WINDOW 70ULL
#define CLKS_SYSCALL_STATS_RECENT_ID 71ULL
void clks_syscall_init(void);
u64 clks_syscall_dispatch(void *frame_ptr);

View File

@@ -32,6 +32,8 @@
#define CLKS_SYSCALL_KDBG_STACK_WINDOW_BYTES (128ULL * 1024ULL)
#define CLKS_SYSCALL_KERNEL_SYMBOL_FILE "/system/kernel.sym"
#define CLKS_SYSCALL_KERNEL_ADDR_BASE 0xFFFF800000000000ULL
#define CLKS_SYSCALL_STATS_MAX_ID CLKS_SYSCALL_STATS_RECENT_ID
#define CLKS_SYSCALL_STATS_RING_SIZE 256U
struct clks_syscall_frame {
u64 rax;
@@ -73,6 +75,12 @@ static clks_bool clks_syscall_last_frame_valid = CLKS_FALSE;
static clks_bool clks_syscall_symbols_checked = CLKS_FALSE;
static const char *clks_syscall_symbols_data = CLKS_NULL;
static u64 clks_syscall_symbols_size = 0ULL;
static u64 clks_syscall_stats_total = 0ULL;
static u64 clks_syscall_stats_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL];
static u64 clks_syscall_stats_recent_id_count[CLKS_SYSCALL_STATS_MAX_ID + 1ULL];
static u16 clks_syscall_stats_recent_ring[CLKS_SYSCALL_STATS_RING_SIZE];
static u32 clks_syscall_stats_recent_head = 0U;
static u32 clks_syscall_stats_recent_size = 0U;
#if defined(CLKS_ARCH_X86_64)
static inline void clks_syscall_outb(u16 port, u8 value) {
@@ -1492,6 +1500,75 @@ static void clks_syscall_serial_write_hex64(u64 value) {
}
}
static void clks_syscall_stats_reset(void) {
clks_syscall_stats_total = 0ULL;
clks_memset(clks_syscall_stats_id_count, 0, sizeof(clks_syscall_stats_id_count));
clks_memset(clks_syscall_stats_recent_id_count, 0, sizeof(clks_syscall_stats_recent_id_count));
clks_memset(clks_syscall_stats_recent_ring, 0, sizeof(clks_syscall_stats_recent_ring));
clks_syscall_stats_recent_head = 0U;
clks_syscall_stats_recent_size = 0U;
}
static void clks_syscall_stats_record(u64 id) {
u16 ring_id = 0xFFFFU;
clks_syscall_stats_total++;
if (id <= CLKS_SYSCALL_STATS_MAX_ID) {
clks_syscall_stats_id_count[id]++;
}
if (id <= 0xFFFFULL) {
ring_id = (u16)id;
}
if (clks_syscall_stats_recent_size >= CLKS_SYSCALL_STATS_RING_SIZE) {
u64 old_id = (u64)clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head];
if (old_id <= CLKS_SYSCALL_STATS_MAX_ID && clks_syscall_stats_recent_id_count[old_id] > 0ULL) {
clks_syscall_stats_recent_id_count[old_id]--;
}
} else {
clks_syscall_stats_recent_size++;
}
clks_syscall_stats_recent_ring[clks_syscall_stats_recent_head] = ring_id;
if (id <= CLKS_SYSCALL_STATS_MAX_ID) {
clks_syscall_stats_recent_id_count[id]++;
}
clks_syscall_stats_recent_head++;
if (clks_syscall_stats_recent_head >= CLKS_SYSCALL_STATS_RING_SIZE) {
clks_syscall_stats_recent_head = 0U;
}
}
static u64 clks_syscall_stats_total_count(void) {
return clks_syscall_stats_total;
}
static u64 clks_syscall_stats_id(u64 id) {
if (id > CLKS_SYSCALL_STATS_MAX_ID) {
return 0ULL;
}
return clks_syscall_stats_id_count[id];
}
static u64 clks_syscall_stats_recent_window(void) {
return (u64)clks_syscall_stats_recent_size;
}
static u64 clks_syscall_stats_recent_id(u64 id) {
if (id > CLKS_SYSCALL_STATS_MAX_ID) {
return 0ULL;
}
return clks_syscall_stats_recent_id_count[id];
}
static void clks_syscall_trace_user_program(u64 id) {
clks_bool user_program_running =
(clks_exec_is_running() == CLKS_TRUE && clks_exec_current_path_is_user() == CLKS_TRUE)
@@ -1538,6 +1615,7 @@ void clks_syscall_init(void) {
clks_syscall_symbols_checked = CLKS_FALSE;
clks_syscall_symbols_data = CLKS_NULL;
clks_syscall_symbols_size = 0ULL;
clks_syscall_stats_reset();
clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE");
}
@@ -1553,6 +1631,7 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
clks_syscall_last_frame_valid = CLKS_TRUE;
id = frame->rax;
clks_syscall_stats_record(id);
clks_syscall_trace_user_program(id);
switch (id) {
@@ -1699,6 +1778,14 @@ u64 clks_syscall_dispatch(void *frame_ptr) {
return clks_syscall_kdbg_bt(frame->rbx);
case CLKS_SYSCALL_KDBG_REGS:
return clks_syscall_kdbg_regs(frame->rbx, frame->rcx);
case CLKS_SYSCALL_STATS_TOTAL:
return clks_syscall_stats_total_count();
case CLKS_SYSCALL_STATS_ID_COUNT:
return clks_syscall_stats_id(frame->rbx);
case CLKS_SYSCALL_STATS_RECENT_WINDOW:
return clks_syscall_stats_recent_window();
case CLKS_SYSCALL_STATS_RECENT_ID:
return clks_syscall_stats_recent_id(frame->rbx);
default:
return (u64)-1;
}

View File

@@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `/proc/<pid>`:指定 PID 快照文本
- `/proc` 为只读;写入类 syscall 不支持。
## 4. Syscall 列表0~64
## 4. Syscall 列表0~71
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -510,6 +510,53 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `SIGSTOP`:将 `PENDING` 进程置为 `STOPPED`;对已 `STOPPED` 目标返回成功。
- `SIGCONT`:将 `STOPPED` 进程恢复为 `PENDING`
### 65 `CLEONOS_SYSCALL_KDBG_SYM`
- 参数:
- `arg0`: `u64 addr`
- `arg1`: `char *out_line`
- `arg2`: `u64 out_size`
- 返回:写入字节数(含截断)
- 说明:将地址符号化为文本(含偏移与可选源码位置)。
### 66 `CLEONOS_SYSCALL_KDBG_BT`
- 参数:
- `arg0`: `struct { u64 rbp; u64 rip; u64 out_ptr; u64 out_size; } *req`
- 返回:写入字节数
- 说明输出回溯文本x86_64 下会尝试沿帧指针遍历。
### 67 `CLEONOS_SYSCALL_KDBG_REGS`
- 参数:
- `arg0`: `char *out_text`
- `arg1`: `u64 out_size`
- 返回:写入字节数
- 说明:输出最近一次 syscall 进入内核时的寄存器快照。
### 68 `CLEONOS_SYSCALL_STATS_TOTAL`
- 参数:无
- 返回:自启动以来的 syscall 总调用次数
### 69 `CLEONOS_SYSCALL_STATS_ID_COUNT`
- 参数:
- `arg0`: `u64 id`
- 返回:指定 syscall ID 的累计调用次数ID 越界返回 `0`
### 70 `CLEONOS_SYSCALL_STATS_RECENT_WINDOW`
- 参数:无
- 返回:最近窗口内样本数量
- 说明:当前内核实现窗口大小为 `256` 次 syscall。
### 71 `CLEONOS_SYSCALL_STATS_RECENT_ID`
- 参数:
- `arg0`: `u64 id`
- 返回:指定 syscall ID 在“最近窗口”中的出现次数ID 越界返回 `0`
## 5. 用户态封装函数
用户态封装位于:
@@ -532,6 +579,8 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `cleonos_sys_proc_argc()` / `cleonos_sys_proc_argv()` / `cleonos_sys_proc_envc()` / `cleonos_sys_proc_env()`
- `cleonos_sys_proc_last_signal()` / `cleonos_sys_proc_fault_vector()` / `cleonos_sys_proc_fault_error()` / `cleonos_sys_proc_fault_rip()`
- `cleonos_sys_proc_count()` / `cleonos_sys_proc_pid_at()` / `cleonos_sys_proc_snapshot()` / `cleonos_sys_proc_kill()`
- `cleonos_sys_kdbg_sym()` / `cleonos_sys_kdbg_bt()` / `cleonos_sys_kdbg_regs()`
- `cleonos_sys_stats_total()` / `cleonos_sys_stats_id_count()` / `cleonos_sys_stats_recent_window()` / `cleonos_sys_stats_recent_id()`
## 6. 开发注意事项
@@ -542,6 +591,6 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
## 7. Wine 兼容说明
- `wine/cleonos_wine_lib/runner.py` 已适配 syscall `0..60`,包含 `EXEC_PATHV` / `SPAWN_PATHV``PROC_*` 系列
- `wine/cleonos_wine_lib/runner.py` 目前以 syscall `0..67` 为主,新增 ID 需同步适配后才能完整观测统计类接口
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0``AUDIO_PLAY_TONE=0``AUDIO_STOP=1`