This commit is contained in:
2026-04-17 17:28:49 +08:00
parent f93af4a2a6
commit 42b5925222
11 changed files with 699 additions and 50 deletions

View File

@@ -1,5 +1,31 @@
#include "cmd_runtime.h" #include "cmd_runtime.h"
static int ush_bg_resume_pid(const char *pid_text) {
u64 pid = 0ULL;
u64 ret;
if (pid_text == (const char *)0 || ush_parse_u64_dec(pid_text, &pid) == 0 || pid == 0ULL) {
return 0;
}
ret = cleonos_sys_proc_kill(pid, CLEONOS_SIGCONT);
if (ret == (u64)-1) {
ush_writeln("bg: pid not found");
return 1;
}
if (ret == 0ULL) {
ush_writeln("bg: target cannot be resumed right now");
return 1;
}
ush_write("bg: resumed [");
ush_write_hex_u64(pid);
ush_writeln("]");
return 1;
}
static int ush_cmd_bg(const ush_state *sh, const char *arg) { static int ush_cmd_bg(const ush_state *sh, const char *arg) {
char target[USH_PATH_MAX]; char target[USH_PATH_MAX];
char argv_line[USH_ARG_MAX]; char argv_line[USH_ARG_MAX];
@@ -23,6 +49,10 @@ static int ush_cmd_bg(const ush_state *sh, const char *arg) {
ush_copy(argv_line, (u64)sizeof(argv_line), rest); ush_copy(argv_line, (u64)sizeof(argv_line), rest);
} }
if (argv_line[0] == '\0' && ush_bg_resume_pid(target) != 0) {
return 1;
}
if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) { if (ush_resolve_exec_path(sh, target, path, (u64)sizeof(path)) == 0) {
ush_writeln("bg: invalid target"); ush_writeln("bg: invalid target");
return 0; return 0;

View File

@@ -52,7 +52,9 @@ static int ush_fg_pick_latest_job(u64 *out_pid) {
continue; continue;
} }
if (snap.state != CLEONOS_PROC_STATE_PENDING && snap.state != CLEONOS_PROC_STATE_RUNNING) { if (snap.state != CLEONOS_PROC_STATE_PENDING &&
snap.state != CLEONOS_PROC_STATE_RUNNING &&
snap.state != CLEONOS_PROC_STATE_STOPPED) {
continue; continue;
} }
@@ -99,6 +101,7 @@ static int ush_fg_wait_pid(u64 pid) {
static int ush_cmd_fg(const char *arg) { static int ush_cmd_fg(const char *arg) {
u64 pid = 0ULL; u64 pid = 0ULL;
cleonos_proc_snapshot snap;
if (arg != (const char *)0 && arg[0] != '\0') { if (arg != (const char *)0 && arg[0] != '\0') {
if (ush_parse_u64_dec(arg, &pid) == 0 || pid == 0ULL) { if (ush_parse_u64_dec(arg, &pid) == 0 || pid == 0ULL) {
@@ -112,6 +115,25 @@ static int ush_cmd_fg(const char *arg) {
} }
} }
if (cleonos_sys_proc_snapshot(pid, &snap, (u64)sizeof(snap)) == 0ULL) {
ush_writeln("fg: pid not found");
return 0;
}
if (snap.state == CLEONOS_PROC_STATE_STOPPED) {
u64 ret = cleonos_sys_proc_kill(pid, CLEONOS_SIGCONT);
if (ret == (u64)-1) {
ush_writeln("fg: pid not found");
return 0;
}
if (ret == 0ULL) {
ush_writeln("fg: failed to continue job");
return 0;
}
}
ush_write("fg: waiting ["); ush_write("fg: waiting [");
ush_write_hex_u64(pid); ush_write_hex_u64(pid);
ush_writeln("]"); ush_writeln("]");

View File

@@ -25,6 +25,9 @@ static const char *ush_jobs_state_name(u64 state) {
if (state == CLEONOS_PROC_STATE_RUNNING) { if (state == CLEONOS_PROC_STATE_RUNNING) {
return "RUNNING"; return "RUNNING";
} }
if (state == CLEONOS_PROC_STATE_STOPPED) {
return "STOPPED";
}
if (state == CLEONOS_PROC_STATE_EXITED) { if (state == CLEONOS_PROC_STATE_EXITED) {
return "EXITED "; return "EXITED ";
} }

View File

@@ -1,19 +1,105 @@
#include "cmd_runtime.h" #include "cmd_runtime.h"
static void ush_kill_upper_copy(char *dst, u64 dst_size, const char *src) {
u64 i = 0ULL;
if (dst == (char *)0 || dst_size == 0ULL) {
return;
}
dst[0] = '\0';
if (src == (const char *)0) {
return;
}
while (src[i] != '\0' && i + 1ULL < dst_size) {
char ch = src[i];
if (ch >= 'a' && ch <= 'z') {
ch = (char)(ch - ('a' - 'A'));
}
dst[i] = ch;
i++;
}
dst[i] = '\0';
}
static int ush_kill_parse_signal_name(const char *text, u64 *out_signal) {
char name[32];
u64 start = 0ULL;
if (text == (const char *)0 || out_signal == (u64 *)0 || text[0] == '\0') {
return 0;
}
ush_kill_upper_copy(name, (u64)sizeof(name), text);
if (name[0] == '-') {
start = 1ULL;
}
if (name[start] == 'S' && name[start + 1ULL] == 'I' && name[start + 2ULL] == 'G') {
start += 3ULL;
}
if (name[start] == '\0') {
return 0;
}
if (ush_streq(&name[start], "TERM") != 0) {
*out_signal = CLEONOS_SIGTERM;
return 1;
}
if (ush_streq(&name[start], "KILL") != 0) {
*out_signal = CLEONOS_SIGKILL;
return 1;
}
if (ush_streq(&name[start], "STOP") != 0) {
*out_signal = CLEONOS_SIGSTOP;
return 1;
}
if (ush_streq(&name[start], "CONT") != 0) {
*out_signal = CLEONOS_SIGCONT;
return 1;
}
return 0;
}
static int ush_kill_parse_signal(const char *text, u64 *out_signal) {
u64 parsed = 0ULL;
if (text == (const char *)0 || out_signal == (u64 *)0 || text[0] == '\0') {
return 0;
}
if (ush_parse_u64_dec(text, &parsed) != 0 && parsed <= 255ULL) {
*out_signal = parsed;
return 1;
}
return ush_kill_parse_signal_name(text, out_signal);
}
static int ush_cmd_kill(const char *arg) { static int ush_cmd_kill(const char *arg) {
char pid_text[USH_PATH_MAX]; char pid_text[USH_PATH_MAX];
char signal_text[USH_PATH_MAX];
const char *rest = ""; const char *rest = "";
u64 pid; u64 pid;
u64 signal = 15ULL; u64 signal = CLEONOS_SIGTERM;
u64 ret; u64 ret;
if (arg == (const char *)0 || arg[0] == '\0') { if (arg == (const char *)0 || arg[0] == '\0') {
ush_writeln("kill: usage kill <pid> [signal]"); ush_writeln("kill: usage kill <pid> [TERM|KILL|STOP|CONT|signal]");
return 0; return 0;
} }
if (ush_split_first_and_rest(arg, pid_text, (u64)sizeof(pid_text), &rest) == 0) { if (ush_split_first_and_rest(arg, pid_text, (u64)sizeof(pid_text), &rest) == 0) {
ush_writeln("kill: usage kill <pid> [signal]"); ush_writeln("kill: usage kill <pid> [TERM|KILL|STOP|CONT|signal]");
return 0; return 0;
} }
@@ -23,7 +109,9 @@ static int ush_cmd_kill(const char *arg) {
} }
if (rest != (const char *)0 && rest[0] != '\0') { if (rest != (const char *)0 && rest[0] != '\0') {
if (ush_parse_u64_dec(rest, &signal) == 0 || signal > 255ULL) { ush_copy(signal_text, (u64)sizeof(signal_text), rest);
ush_trim_line(signal_text);
if (ush_kill_parse_signal(signal_text, &signal) == 0) {
ush_writeln("kill: invalid signal"); ush_writeln("kill: invalid signal");
return 0; return 0;
} }

View File

@@ -25,6 +25,9 @@ static const char *ush_ps_state_name(u64 state) {
if (state == CLEONOS_PROC_STATE_RUNNING) { if (state == CLEONOS_PROC_STATE_RUNNING) {
return "RUN "; return "RUN ";
} }
if (state == CLEONOS_PROC_STATE_STOPPED) {
return "STOP";
}
if (state == CLEONOS_PROC_STATE_EXITED) { if (state == CLEONOS_PROC_STATE_EXITED) {
return "EXIT"; return "EXIT";
} }

View File

@@ -7,6 +7,9 @@ static const char *ush_top_state_name(u64 state) {
if (state == CLEONOS_PROC_STATE_RUNNING) { if (state == CLEONOS_PROC_STATE_RUNNING) {
return "RUN "; return "RUN ";
} }
if (state == CLEONOS_PROC_STATE_STOPPED) {
return "STOP";
}
if (state == CLEONOS_PROC_STATE_EXITED) { if (state == CLEONOS_PROC_STATE_EXITED) {
return "EXIT"; return "EXIT";
} }
@@ -114,7 +117,9 @@ static void ush_top_render_frame(u64 frame_index, u64 delay_ticks) {
continue; continue;
} }
if (snap.state != CLEONOS_PROC_STATE_PENDING && snap.state != CLEONOS_PROC_STATE_RUNNING) { if (snap.state != CLEONOS_PROC_STATE_PENDING &&
snap.state != CLEONOS_PROC_STATE_RUNNING &&
snap.state != CLEONOS_PROC_STATE_STOPPED) {
continue; continue;
} }

View File

@@ -11,6 +11,12 @@ typedef unsigned long long usize;
#define CLEONOS_PROC_STATE_PENDING 1ULL #define CLEONOS_PROC_STATE_PENDING 1ULL
#define CLEONOS_PROC_STATE_RUNNING 2ULL #define CLEONOS_PROC_STATE_RUNNING 2ULL
#define CLEONOS_PROC_STATE_EXITED 3ULL #define CLEONOS_PROC_STATE_EXITED 3ULL
#define CLEONOS_PROC_STATE_STOPPED 4ULL
#define CLEONOS_SIGKILL 9ULL
#define CLEONOS_SIGTERM 15ULL
#define CLEONOS_SIGCONT 18ULL
#define CLEONOS_SIGSTOP 19ULL
typedef struct cleonos_proc_snapshot { typedef struct cleonos_proc_snapshot {
u64 pid; u64 pid;

View File

@@ -9,6 +9,12 @@
#define CLKS_EXEC_PROC_STATE_PENDING 1ULL #define CLKS_EXEC_PROC_STATE_PENDING 1ULL
#define CLKS_EXEC_PROC_STATE_RUNNING 2ULL #define CLKS_EXEC_PROC_STATE_RUNNING 2ULL
#define CLKS_EXEC_PROC_STATE_EXITED 3ULL #define CLKS_EXEC_PROC_STATE_EXITED 3ULL
#define CLKS_EXEC_PROC_STATE_STOPPED 4ULL
#define CLKS_EXEC_SIGNAL_KILL 9ULL
#define CLKS_EXEC_SIGNAL_TERM 15ULL
#define CLKS_EXEC_SIGNAL_CONT 18ULL
#define CLKS_EXEC_SIGNAL_STOP 19ULL
struct clks_exec_proc_snapshot { struct clks_exec_proc_snapshot {
u64 pid; u64 pid;

View File

@@ -22,13 +22,14 @@ typedef u64 (*clks_exec_entry_fn)(void);
#define CLKS_EXEC_MAX_ENVS 24U #define CLKS_EXEC_MAX_ENVS 24U
#define CLKS_EXEC_ITEM_MAX 128U #define CLKS_EXEC_ITEM_MAX 128U
#define CLKS_EXEC_STATUS_SIGNAL_FLAG (1ULL << 63) #define CLKS_EXEC_STATUS_SIGNAL_FLAG (1ULL << 63)
#define CLKS_EXEC_DEFAULT_KILL_SIGNAL 15ULL #define CLKS_EXEC_DEFAULT_KILL_SIGNAL CLKS_EXEC_SIGNAL_TERM
enum clks_exec_proc_state { enum clks_exec_proc_state {
CLKS_EXEC_PROC_UNUSED = 0, CLKS_EXEC_PROC_UNUSED = 0,
CLKS_EXEC_PROC_PENDING = 1, CLKS_EXEC_PROC_PENDING = 1,
CLKS_EXEC_PROC_RUNNING = 2, CLKS_EXEC_PROC_RUNNING = 2,
CLKS_EXEC_PROC_EXITED = 3, CLKS_EXEC_PROC_EXITED = 3,
CLKS_EXEC_PROC_STOPPED = 4,
}; };
struct clks_exec_proc_record { struct clks_exec_proc_record {
@@ -38,6 +39,8 @@ struct clks_exec_proc_record {
u64 ppid; u64 ppid;
u64 started_tick; u64 started_tick;
u64 exited_tick; u64 exited_tick;
u64 run_started_tick;
u64 runtime_ticks_accum;
u64 exit_status; u64 exit_status;
u32 tty_index; u32 tty_index;
u64 image_mem_bytes; u64 image_mem_bytes;
@@ -413,6 +416,8 @@ static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
proc->ppid = clks_exec_current_pid(); proc->ppid = clks_exec_current_pid();
proc->started_tick = 0ULL; proc->started_tick = 0ULL;
proc->exited_tick = 0ULL; proc->exited_tick = 0ULL;
proc->run_started_tick = 0ULL;
proc->runtime_ticks_accum = 0ULL;
proc->exit_status = (u64)-1; proc->exit_status = (u64)-1;
proc->tty_index = clks_tty_active(); proc->tty_index = clks_tty_active();
proc->image_mem_bytes = 0ULL; proc->image_mem_bytes = 0ULL;
@@ -446,6 +451,42 @@ static struct clks_exec_proc_record *clks_exec_prepare_proc_record(i32 slot,
return proc; return proc;
} }
static void clks_exec_proc_mark_running(struct clks_exec_proc_record *proc, u64 now_tick) {
if (proc == CLKS_NULL) {
return;
}
if (proc->started_tick == 0ULL) {
proc->started_tick = now_tick;
}
proc->run_started_tick = now_tick;
proc->state = CLKS_EXEC_PROC_RUNNING;
}
static void clks_exec_proc_pause_runtime(struct clks_exec_proc_record *proc, u64 now_tick) {
if (proc == CLKS_NULL) {
return;
}
if (proc->run_started_tick != 0ULL && now_tick > proc->run_started_tick) {
proc->runtime_ticks_accum += (now_tick - proc->run_started_tick);
}
proc->run_started_tick = 0ULL;
}
static void clks_exec_proc_mark_exited(struct clks_exec_proc_record *proc, u64 now_tick, u64 status) {
if (proc == CLKS_NULL) {
return;
}
clks_exec_proc_pause_runtime(proc, now_tick);
proc->state = CLKS_EXEC_PROC_EXITED;
proc->exit_status = status;
proc->exited_tick = now_tick;
}
static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *out_ret) { static clks_bool clks_exec_invoke_entry(void *entry_ptr, u32 depth_index, u64 *out_ret) {
if (entry_ptr == CLKS_NULL || out_ret == CLKS_NULL) { if (entry_ptr == CLKS_NULL || out_ret == CLKS_NULL) {
return CLKS_FALSE; return CLKS_FALSE;
@@ -509,22 +550,17 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) {
} }
if (proc->path[0] != '/') { if (proc->path[0] != '/') {
proc->state = CLKS_EXEC_PROC_EXITED; clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1);
proc->exit_status = (u64)-1;
proc->exited_tick = clks_interrupts_timer_ticks();
return CLKS_FALSE; return CLKS_FALSE;
} }
if (clks_exec_pid_stack_depth >= CLKS_EXEC_MAX_DEPTH) { if (clks_exec_pid_stack_depth >= CLKS_EXEC_MAX_DEPTH) {
clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS STACK DEPTH EXCEEDED"); clks_log(CLKS_LOG_WARN, "EXEC", "PROCESS STACK DEPTH EXCEEDED");
proc->state = CLKS_EXEC_PROC_EXITED; clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1);
proc->exit_status = (u64)-1;
proc->exited_tick = clks_interrupts_timer_ticks();
return CLKS_FALSE; return CLKS_FALSE;
} }
proc->state = CLKS_EXEC_PROC_RUNNING; clks_exec_proc_mark_running(proc, clks_interrupts_timer_ticks());
proc->started_tick = clks_interrupts_timer_ticks();
depth_index = (i32)clks_exec_pid_stack_depth; depth_index = (i32)clks_exec_pid_stack_depth;
clks_exec_pid_stack[(u32)depth_index] = proc->pid; clks_exec_pid_stack[(u32)depth_index] = proc->pid;
@@ -593,9 +629,7 @@ static clks_bool clks_exec_run_proc_slot(i32 slot, u64 *out_status) {
clks_exec_success++; clks_exec_success++;
proc->state = CLKS_EXEC_PROC_EXITED; clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), run_ret);
proc->exit_status = run_ret;
proc->exited_tick = clks_interrupts_timer_ticks();
if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) {
clks_exec_pid_stack_depth--; clks_exec_pid_stack_depth--;
@@ -617,9 +651,7 @@ fail:
clks_exec_running_depth--; clks_exec_running_depth--;
} }
proc->state = CLKS_EXEC_PROC_EXITED; clks_exec_proc_mark_exited(proc, clks_interrupts_timer_ticks(), (u64)-1);
proc->exit_status = (u64)-1;
proc->exited_tick = clks_interrupts_timer_ticks();
if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) { if (depth_pushed == CLKS_TRUE && clks_exec_pid_stack_depth > 0U) {
clks_exec_pid_stack_depth--; clks_exec_pid_stack_depth--;
@@ -805,7 +837,9 @@ u64 clks_exec_wait_pid(u64 pid, u64 *out_status) {
clks_exec_pending_dispatch_active = CLKS_FALSE; clks_exec_pending_dispatch_active = CLKS_FALSE;
} }
if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_RUNNING) { if (proc->state == CLKS_EXEC_PROC_PENDING ||
proc->state == CLKS_EXEC_PROC_RUNNING ||
proc->state == CLKS_EXEC_PROC_STOPPED) {
return 0ULL; return 0ULL;
} }
@@ -964,27 +998,21 @@ u64 clks_exec_current_fault_rip(void) {
} }
static u64 clks_exec_proc_runtime_ticks(const struct clks_exec_proc_record *proc, u64 now_tick) { static u64 clks_exec_proc_runtime_ticks(const struct clks_exec_proc_record *proc, u64 now_tick) {
u64 runtime;
if (proc == CLKS_NULL || proc->started_tick == 0ULL) { if (proc == CLKS_NULL || proc->started_tick == 0ULL) {
return 0ULL; return 0ULL;
} }
if (proc->state == CLKS_EXEC_PROC_RUNNING) { runtime = proc->runtime_ticks_accum;
if (now_tick <= proc->started_tick) {
return 0ULL; if (proc->state == CLKS_EXEC_PROC_RUNNING &&
proc->run_started_tick != 0ULL &&
now_tick > proc->run_started_tick) {
runtime += (now_tick - proc->run_started_tick);
} }
return now_tick - proc->started_tick; return runtime;
}
if (proc->state == CLKS_EXEC_PROC_EXITED) {
if (proc->exited_tick <= proc->started_tick) {
return 0ULL;
}
return proc->exited_tick - proc->started_tick;
}
return 0ULL;
} }
static u64 clks_exec_proc_memory_bytes(const struct clks_exec_proc_record *proc) { static u64 clks_exec_proc_memory_bytes(const struct clks_exec_proc_record *proc) {
@@ -1117,14 +1145,33 @@ u64 clks_exec_proc_kill(u64 pid, u64 signal) {
return 1ULL; return 1ULL;
} }
if (proc->state == CLKS_EXEC_PROC_PENDING) {
proc->state = CLKS_EXEC_PROC_EXITED;
proc->exit_status = status;
proc->exited_tick = now_tick;
proc->last_signal = effective_signal; proc->last_signal = effective_signal;
proc->last_fault_vector = 0ULL; proc->last_fault_vector = 0ULL;
proc->last_fault_error = 0ULL; proc->last_fault_error = 0ULL;
proc->last_fault_rip = 0ULL; proc->last_fault_rip = 0ULL;
if (effective_signal == CLKS_EXEC_SIGNAL_CONT) {
if (proc->state == CLKS_EXEC_PROC_STOPPED) {
proc->state = CLKS_EXEC_PROC_PENDING;
}
return 1ULL;
}
if (effective_signal == CLKS_EXEC_SIGNAL_STOP) {
if (proc->state == CLKS_EXEC_PROC_PENDING) {
proc->state = CLKS_EXEC_PROC_STOPPED;
return 1ULL;
}
if (proc->state == CLKS_EXEC_PROC_STOPPED) {
return 1ULL;
}
return 0ULL;
}
if (proc->state == CLKS_EXEC_PROC_PENDING || proc->state == CLKS_EXEC_PROC_STOPPED) {
clks_exec_proc_mark_exited(proc, now_tick, status);
return 1ULL; return 1ULL;
} }
@@ -1135,10 +1182,6 @@ u64 clks_exec_proc_kill(u64 pid, u64 signal) {
return 0ULL; return 0ULL;
} }
proc->last_signal = effective_signal;
proc->last_fault_vector = 0ULL;
proc->last_fault_error = 0ULL;
proc->last_fault_rip = 0ULL;
clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE; clks_exec_exit_requested_stack[(u32)depth_index] = CLKS_TRUE;
clks_exec_exit_status_stack[(u32)depth_index] = status; clks_exec_exit_status_stack[(u32)depth_index] = status;
return 1ULL; return 1ULL;

View File

@@ -25,6 +25,7 @@
#define CLKS_SYSCALL_ARG_LINE_MAX 256U #define CLKS_SYSCALL_ARG_LINE_MAX 256U
#define CLKS_SYSCALL_ENV_LINE_MAX 512U #define CLKS_SYSCALL_ENV_LINE_MAX 512U
#define CLKS_SYSCALL_ITEM_MAX 128U #define CLKS_SYSCALL_ITEM_MAX 128U
#define CLKS_SYSCALL_PROCFS_TEXT_MAX 2048U
#define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL #define CLKS_SYSCALL_USER_TRACE_BUDGET 128ULL
struct clks_syscall_frame { struct clks_syscall_frame {
@@ -166,6 +167,333 @@ static u64 clks_syscall_kbd_get_char(void) {
return (u64)(u8)ch; return (u64)(u8)ch;
} }
static clks_bool clks_syscall_procfs_is_root(const char *path) {
return (path != CLKS_NULL && clks_strcmp(path, "/proc") == 0) ? CLKS_TRUE : CLKS_FALSE;
}
static clks_bool clks_syscall_procfs_is_self(const char *path) {
return (path != CLKS_NULL && clks_strcmp(path, "/proc/self") == 0) ? CLKS_TRUE : CLKS_FALSE;
}
static clks_bool clks_syscall_procfs_is_list(const char *path) {
return (path != CLKS_NULL && clks_strcmp(path, "/proc/list") == 0) ? CLKS_TRUE : CLKS_FALSE;
}
static clks_bool clks_syscall_parse_u64_dec(const char *text, u64 *out_value) {
u64 value = 0ULL;
usize i = 0U;
if (text == CLKS_NULL || out_value == CLKS_NULL || text[0] == '\0') {
return CLKS_FALSE;
}
while (text[i] != '\0') {
u64 digit;
if (text[i] < '0' || text[i] > '9') {
return CLKS_FALSE;
}
digit = (u64)(text[i] - '0');
if (value > ((0xFFFFFFFFFFFFFFFFULL - digit) / 10ULL)) {
return CLKS_FALSE;
}
value = (value * 10ULL) + digit;
i++;
}
*out_value = value;
return CLKS_TRUE;
}
static clks_bool clks_syscall_procfs_parse_pid(const char *path, u64 *out_pid) {
const char *part;
usize i = 0U;
char pid_text[32];
u64 pid;
if (path == CLKS_NULL || out_pid == CLKS_NULL) {
return CLKS_FALSE;
}
if (path[0] != '/' || path[1] != 'p' || path[2] != 'r' || path[3] != 'o' || path[4] != 'c' || path[5] != '/') {
return CLKS_FALSE;
}
part = &path[6];
if (part[0] == '\0' || clks_strcmp(part, "self") == 0 || clks_strcmp(part, "list") == 0) {
return CLKS_FALSE;
}
while (part[i] != '\0') {
if (i + 1U >= sizeof(pid_text)) {
return CLKS_FALSE;
}
if (part[i] < '0' || part[i] > '9') {
return CLKS_FALSE;
}
pid_text[i] = part[i];
i++;
}
pid_text[i] = '\0';
if (clks_syscall_parse_u64_dec(pid_text, &pid) == CLKS_FALSE || pid == 0ULL) {
return CLKS_FALSE;
}
*out_pid = pid;
return CLKS_TRUE;
}
static const char *clks_syscall_proc_state_name(u64 state) {
if (state == CLKS_EXEC_PROC_STATE_PENDING) {
return "PENDING";
}
if (state == CLKS_EXEC_PROC_STATE_RUNNING) {
return "RUNNING";
}
if (state == CLKS_EXEC_PROC_STATE_STOPPED) {
return "STOPPED";
}
if (state == CLKS_EXEC_PROC_STATE_EXITED) {
return "EXITED";
}
return "UNUSED";
}
static usize clks_syscall_procfs_append_char(char *out, usize out_size, usize pos, char ch) {
if (out == CLKS_NULL || out_size == 0U) {
return pos;
}
if (pos + 1U < out_size) {
out[pos] = ch;
out[pos + 1U] = '\0';
return pos + 1U;
}
out[out_size - 1U] = '\0';
return pos;
}
static usize clks_syscall_procfs_append_text(char *out, usize out_size, usize pos, const char *text) {
usize i = 0U;
if (text == CLKS_NULL) {
return pos;
}
while (text[i] != '\0') {
pos = clks_syscall_procfs_append_char(out, out_size, pos, text[i]);
i++;
}
return pos;
}
static usize clks_syscall_procfs_append_u64_dec(char *out, usize out_size, usize pos, u64 value) {
char temp[32];
usize len = 0U;
usize i;
if (value == 0ULL) {
return clks_syscall_procfs_append_char(out, out_size, pos, '0');
}
while (value != 0ULL && len + 1U < sizeof(temp)) {
temp[len++] = (char)('0' + (value % 10ULL));
value /= 10ULL;
}
for (i = 0U; i < len; i++) {
pos = clks_syscall_procfs_append_char(out, out_size, pos, temp[len - 1U - i]);
}
return pos;
}
static usize clks_syscall_procfs_append_u64_hex(char *out, usize out_size, usize pos, u64 value) {
i32 nibble;
pos = clks_syscall_procfs_append_text(out, out_size, pos, "0X");
for (nibble = 15; nibble >= 0; nibble--) {
u64 current = (value >> (u64)(nibble * 4)) & 0x0FULL;
char ch = (current < 10ULL) ? (char)('0' + current) : (char)('A' + (current - 10ULL));
pos = clks_syscall_procfs_append_char(out, out_size, pos, ch);
}
return pos;
}
static clks_bool clks_syscall_procfs_snapshot_for_path(const char *path, struct clks_exec_proc_snapshot *out_snap) {
u64 pid;
if (path == CLKS_NULL || out_snap == CLKS_NULL) {
return CLKS_FALSE;
}
if (clks_syscall_procfs_is_self(path) == CLKS_TRUE) {
pid = clks_exec_current_pid();
if (pid == 0ULL) {
return CLKS_FALSE;
}
return clks_exec_proc_snapshot(pid, out_snap);
}
if (clks_syscall_procfs_parse_pid(path, &pid) == CLKS_TRUE) {
return clks_exec_proc_snapshot(pid, out_snap);
}
return CLKS_FALSE;
}
static usize clks_syscall_procfs_render_snapshot(char *out,
usize out_size,
const struct clks_exec_proc_snapshot *snap) {
usize pos = 0U;
if (out == CLKS_NULL || out_size == 0U || snap == CLKS_NULL) {
return 0U;
}
out[0] = '\0';
pos = clks_syscall_procfs_append_text(out, out_size, pos, "pid=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->pid);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "ppid=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->ppid);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "state=");
pos = clks_syscall_procfs_append_text(out, out_size, pos, clks_syscall_proc_state_name(snap->state));
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "state_id=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->state);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "tty=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->tty_index);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "runtime_ticks=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->runtime_ticks);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "mem_bytes=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->mem_bytes);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "exit_status=");
pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->exit_status);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_signal=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->last_signal);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_vector=");
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap->last_fault_vector);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_error=");
pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->last_fault_error);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "last_fault_rip=");
pos = clks_syscall_procfs_append_u64_hex(out, out_size, pos, snap->last_fault_rip);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
pos = clks_syscall_procfs_append_text(out, out_size, pos, "path=");
pos = clks_syscall_procfs_append_text(out, out_size, pos, snap->path);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
return pos;
}
static usize clks_syscall_procfs_render_list(char *out, usize out_size) {
usize pos = 0U;
u64 proc_count = clks_exec_proc_count();
u64 i;
if (out == CLKS_NULL || out_size == 0U) {
return 0U;
}
out[0] = '\0';
pos = clks_syscall_procfs_append_text(out, out_size, pos, "pid state tty runtime mem path\n");
for (i = 0ULL; i < proc_count; i++) {
u64 pid = 0ULL;
struct clks_exec_proc_snapshot snap;
if (clks_exec_proc_pid_at(i, &pid) == CLKS_FALSE || pid == 0ULL) {
continue;
}
if (clks_exec_proc_snapshot(pid, &snap) == CLKS_FALSE) {
continue;
}
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.pid);
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
pos = clks_syscall_procfs_append_text(out, out_size, pos, clks_syscall_proc_state_name(snap.state));
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.tty_index);
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.runtime_ticks);
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
pos = clks_syscall_procfs_append_u64_dec(out, out_size, pos, snap.mem_bytes);
pos = clks_syscall_procfs_append_char(out, out_size, pos, ' ');
pos = clks_syscall_procfs_append_text(out, out_size, pos, snap.path);
pos = clks_syscall_procfs_append_char(out, out_size, pos, '\n');
}
return pos;
}
static clks_bool clks_syscall_procfs_render_file(const char *path,
char *out,
usize out_size,
usize *out_len) {
struct clks_exec_proc_snapshot snap;
if (out_len != CLKS_NULL) {
*out_len = 0U;
}
if (path == CLKS_NULL || out == CLKS_NULL || out_size == 0U || out_len == CLKS_NULL) {
return CLKS_FALSE;
}
if (clks_syscall_procfs_is_list(path) == CLKS_TRUE) {
*out_len = clks_syscall_procfs_render_list(out, out_size);
return CLKS_TRUE;
}
if (clks_syscall_procfs_snapshot_for_path(path, &snap) == CLKS_TRUE) {
*out_len = clks_syscall_procfs_render_snapshot(out, out_size, &snap);
return CLKS_TRUE;
}
return CLKS_FALSE;
}
static u64 clks_syscall_fs_child_count(u64 arg0) { static u64 clks_syscall_fs_child_count(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX]; char path[CLKS_SYSCALL_PATH_MAX];
@@ -173,6 +501,10 @@ static u64 clks_syscall_fs_child_count(u64 arg0) {
return (u64)-1; return (u64)-1;
} }
if (clks_syscall_procfs_is_root(path) == CLKS_TRUE) {
return 2ULL + clks_exec_proc_count();
}
return clks_fs_count_children(path); return clks_fs_count_children(path);
} }
@@ -187,6 +519,41 @@ static u64 clks_syscall_fs_get_child_name(u64 arg0, u64 arg1, u64 arg2) {
return 0ULL; return 0ULL;
} }
if (clks_syscall_procfs_is_root(path) == CLKS_TRUE) {
if (arg1 == 0ULL) {
clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX);
clks_memcpy((void *)arg2, "self", 5U);
return 1ULL;
}
if (arg1 == 1ULL) {
clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX);
clks_memcpy((void *)arg2, "list", 5U);
return 1ULL;
}
{
u64 pid = 0ULL;
char pid_text[32];
usize len;
if (clks_exec_proc_pid_at(arg1 - 2ULL, &pid) == CLKS_FALSE || pid == 0ULL) {
return 0ULL;
}
clks_memset(pid_text, 0, sizeof(pid_text));
len = clks_syscall_procfs_append_u64_dec(pid_text, sizeof(pid_text), 0U, pid);
if (len + 1U > CLKS_SYSCALL_NAME_MAX) {
return 0ULL;
}
clks_memset((void *)arg2, 0, CLKS_SYSCALL_NAME_MAX);
clks_memcpy((void *)arg2, pid_text, len + 1U);
return 1ULL;
}
}
if (clks_fs_get_child_name(path, arg1, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) { if (clks_fs_get_child_name(path, arg1, (char *)arg2, (usize)CLKS_SYSCALL_NAME_MAX) == CLKS_FALSE) {
return 0ULL; return 0ULL;
} }
@@ -208,6 +575,26 @@ static u64 clks_syscall_fs_read(u64 arg0, u64 arg1, u64 arg2) {
return 0ULL; return 0ULL;
} }
if (clks_syscall_procfs_is_list(path) == CLKS_TRUE ||
clks_syscall_procfs_is_self(path) == CLKS_TRUE ||
clks_syscall_procfs_parse_pid(path, &file_size) == CLKS_TRUE) {
char proc_text[CLKS_SYSCALL_PROCFS_TEXT_MAX];
usize proc_len = 0U;
if (clks_syscall_procfs_render_file(path, proc_text, sizeof(proc_text), &proc_len) == CLKS_FALSE) {
return 0ULL;
}
copy_len = ((u64)proc_len < arg2) ? (u64)proc_len : arg2;
if (copy_len == 0ULL) {
return 0ULL;
}
clks_memcpy((void *)arg1, proc_text, (usize)copy_len);
return copy_len;
}
data = clks_fs_read_all(path, &file_size); data = clks_fs_read_all(path, &file_size);
if (data == CLKS_NULL || file_size == 0ULL) { if (data == CLKS_NULL || file_size == 0ULL) {
@@ -452,11 +839,24 @@ static u64 clks_syscall_audio_stop(void) {
static u64 clks_syscall_fs_stat_type(u64 arg0) { static u64 clks_syscall_fs_stat_type(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX]; char path[CLKS_SYSCALL_PATH_MAX];
struct clks_fs_node_info info; struct clks_fs_node_info info;
struct clks_exec_proc_snapshot snap;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1; return (u64)-1;
} }
if (clks_syscall_procfs_is_root(path) == CLKS_TRUE) {
return (u64)CLKS_FS_NODE_DIR;
}
if (clks_syscall_procfs_is_list(path) == CLKS_TRUE || clks_syscall_procfs_is_self(path) == CLKS_TRUE) {
return (u64)CLKS_FS_NODE_FILE;
}
if (clks_syscall_procfs_snapshot_for_path(path, &snap) == CLKS_TRUE) {
return (u64)CLKS_FS_NODE_FILE;
}
if (clks_fs_stat(path, &info) == CLKS_FALSE) { if (clks_fs_stat(path, &info) == CLKS_FALSE) {
return (u64)-1; return (u64)-1;
} }
@@ -467,11 +867,21 @@ static u64 clks_syscall_fs_stat_type(u64 arg0) {
static u64 clks_syscall_fs_stat_size(u64 arg0) { static u64 clks_syscall_fs_stat_size(u64 arg0) {
char path[CLKS_SYSCALL_PATH_MAX]; char path[CLKS_SYSCALL_PATH_MAX];
struct clks_fs_node_info info; struct clks_fs_node_info info;
char proc_text[CLKS_SYSCALL_PROCFS_TEXT_MAX];
usize proc_len = 0U;
if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) { if (clks_syscall_copy_user_string(arg0, path, sizeof(path)) == CLKS_FALSE) {
return (u64)-1; return (u64)-1;
} }
if (clks_syscall_procfs_is_root(path) == CLKS_TRUE) {
return 0ULL;
}
if (clks_syscall_procfs_render_file(path, proc_text, sizeof(proc_text), &proc_len) == CLKS_TRUE) {
return (u64)proc_len;
}
if (clks_fs_stat(path, &info) == CLKS_FALSE) { if (clks_fs_stat(path, &info) == CLKS_FALSE) {
return (u64)-1; return (u64)-1;
} }

View File

@@ -44,6 +44,21 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- bits `15:8` = CPU exception vector - bits `15:8` = CPU exception vector
- bits `31:16` = exception error code 低 16 位 - bits `31:16` = exception error code 低 16 位
进程状态值(`proc_snapshot.state`
- `0` = `UNUSED`
- `1` = `PENDING`
- `2` = `RUNNING`
- `3` = `EXITED`
- `4` = `STOPPED`
常用信号值(`PROC_KILL`
- `SIGKILL` = `9`
- `SIGTERM` = `15`
- `SIGCONT` = `18`
- `SIGSTOP` = `19`
## 3. 当前实现中的长度/路径限制 ## 3. 当前实现中的长度/路径限制
以下限制由内核 `clks/kernel/syscall.c` 当前实现决定: 以下限制由内核 `clks/kernel/syscall.c` 当前实现决定:
@@ -60,6 +75,14 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `FS_MKDIR` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` 仅允许 `/temp` 树下路径。 - `FS_MKDIR` / `FS_WRITE` / `FS_APPEND` / `FS_REMOVE` 仅允许 `/temp` 树下路径。
`/proc` 虚拟目录(由 syscall 层动态导出):
- `/proc`目录children = `self``list`、以及全部 PID 名称)
- `/proc/self`:当前进程快照文本
- `/proc/list`:所有进程列表文本
- `/proc/<pid>`:指定 PID 快照文本
- `/proc` 为只读;写入类 syscall 不支持。
## 4. Syscall 列表0~64 ## 4. Syscall 列表0~64
### 0 `CLEONOS_SYSCALL_LOG_WRITE` ### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -120,6 +143,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 参数: - 参数:
- `arg0`: `const char *dir_path` - `arg0`: `const char *dir_path`
- 返回:子节点数量 - 返回:子节点数量
- 说明:当 `dir_path=/proc` 时,返回 `2 + proc_count``self``list`、PID 子项)。
### 11 `CLEONOS_SYSCALL_FS_GET_CHILD_NAME` ### 11 `CLEONOS_SYSCALL_FS_GET_CHILD_NAME`
@@ -129,6 +153,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `arg2`: `char *out_name` - `arg2`: `char *out_name`
- 返回:成功 `1`,失败 `0` - 返回:成功 `1`,失败 `0`
- 说明:最多写入 96 字节(含终止符)。 - 说明:最多写入 96 字节(含终止符)。
- 说明:当 `dir_path=/proc` 时,`index=0/1` 分别为 `self/list`,后续索引为 PID 文本。
### 12 `CLEONOS_SYSCALL_FS_READ` ### 12 `CLEONOS_SYSCALL_FS_READ`
@@ -138,6 +163,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `arg2`: `u64 buffer_size` - `arg2`: `u64 buffer_size`
- 返回:实际读取字节数,失败/文件空返回 `0` - 返回:实际读取字节数,失败/文件空返回 `0`
- 说明:不会自动追加 `\0`,调用方应自行处理文本终止。 - 说明:不会自动追加 `\0`,调用方应自行处理文本终止。
- 说明:支持读取 `/proc/self``/proc/list``/proc/<pid>`
### 13 `CLEONOS_SYSCALL_EXEC_PATH` ### 13 `CLEONOS_SYSCALL_EXEC_PATH`
@@ -224,12 +250,14 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 参数: - 参数:
- `arg0`: `const char *path` - `arg0`: `const char *path`
- 返回:`1=FILE``2=DIR`,失败 `-1` - 返回:`1=FILE``2=DIR`,失败 `-1`
- 说明:`/proc` 返回目录,`/proc/self``/proc/list``/proc/<pid>` 返回文件。
### 28 `CLEONOS_SYSCALL_FS_STAT_SIZE` ### 28 `CLEONOS_SYSCALL_FS_STAT_SIZE`
- 参数: - 参数:
- `arg0`: `const char *path` - `arg0`: `const char *path`
- 返回:文件大小;目录通常为 `0`;失败 `-1` - 返回:文件大小;目录通常为 `0`;失败 `-1`
- 说明:`/proc/*` 文件大小按生成文本长度返回。
### 29 `CLEONOS_SYSCALL_FS_MKDIR` ### 29 `CLEONOS_SYSCALL_FS_MKDIR`
@@ -323,7 +351,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `arg1`: `u64 *out_status`(可为 `0` - `arg1`: `u64 *out_status`(可为 `0`
- 返回: - 返回:
- `-1`PID 不存在 - `-1`PID 不存在
- `0`:目标进程仍在运行 - `0`:目标进程仍未退出(`PENDING` / `RUNNING` / `STOPPED`
- `1`:目标进程已退出 - `1`:目标进程已退出
- 说明:当返回 `1``arg1!=0` 时,会写入退出码。 - 说明:当返回 `1``arg1!=0` 时,会写入退出码。
@@ -466,7 +494,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `arg1`: `struct cleonos_proc_snapshot *out_snapshot` - `arg1`: `struct cleonos_proc_snapshot *out_snapshot`
- `arg2`: `u64 out_size`(需 `>= sizeof(cleonos_proc_snapshot)` - `arg2`: `u64 out_size`(需 `>= sizeof(cleonos_proc_snapshot)`
- 返回:成功 `1`,失败 `0` - 返回:成功 `1`,失败 `0`
- 说明:返回 PID/PPID/状态/运行 tick/内存估算/TTY/路径等快照信息。 - 说明:返回 PID/PPID/状态(含 `STOPPED`/运行 tick/内存估算/TTY/路径等快照信息。
### 64 `CLEONOS_SYSCALL_PROC_KILL` ### 64 `CLEONOS_SYSCALL_PROC_KILL`
@@ -477,6 +505,10 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `1`:请求成功 - `1`:请求成功
- `0`:当前不可终止(例如非当前上下文中的 running 进程) - `0`:当前不可终止(例如非当前上下文中的 running 进程)
- `-1`PID 不存在 - `-1`PID 不存在
- 语义:
- `SIGTERM`/`SIGKILL`(以及其它非 STOP/CONT 信号):终止目标进程。
- `SIGSTOP`:将 `PENDING` 进程置为 `STOPPED`;对已 `STOPPED` 目标返回成功。
- `SIGCONT`:将 `STOPPED` 进程恢复为 `PENDING`
## 5. 用户态封装函数 ## 5. 用户态封装函数
@@ -506,6 +538,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。 - 传入的字符串/缓冲指针目前按“同地址空间可直接访问”模型处理,后续若引入严格用户态地址隔离,需要补充用户内存校验。
- `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'` - `FS_READ` 不保证文本终止符;读取文本请预留 1 字节并手动 `buf[n] = '\0'`
- `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。 - `FS_WRITE`/`FS_APPEND` 仅允许 `/temp`,并有单次长度上限。
- `/proc` 由 syscall 层虚拟导出,不占用 RAMDISK 节点,也不能通过写入类 syscall 修改。
## 7. Wine 兼容说明 ## 7. Wine 兼容说明