+ 多进程
+ 14个常见的Linux/POSIX系统调用([附录1](#appendix1))
+ 用户模式
-+ 信号机制(进行中)
++ 信号机制(测试中)
## 目录结构
## 附录1:支持的系统调用<a id="appendix1"></a>
### Unix/Linux/POSIX
-1. `sleep(2)`
+1. `sleep(3)`
1. `wait(2)`
1. `waitpid(2)`
1. `fork(2)`
1. `_exit(2)`
1. `sigreturn(2)`
1. `sigprocmask(2)`
-1. `signal(2) `
+1. `signal(2)`
+1. `kill(2)`
### LunaixOS自有
__LXSYSCALL(int, pause)
+__LXSYSCALL2(int, kill, pid_t, pid, int, signum)
+
#endif /* __LUNAIX_UNISTD_H */
--- /dev/null
+#ifndef __LUNAIX_LXSIGNAL_H
+#define __LUNAIX_LXSIGNAL_H
+
+#include <lunaix/types.h>
+
+int
+signal_send(pid_t pid, int signum);
+
+#endif /* __LUNAIX_LXSIGNAL_H */
#define PROC_TERMMASK 0x6
#define PROC_FINPAUSE 1
+#define PROC_FALRMSET (1 << 1)
struct proc_mm
{
int32_t k_status;
sigset_t sig_pending;
sigset_t sig_mask;
+ sigset_t sig_inprogress;
int flags;
void* sig_handler[_SIG_NUM];
pid_t pgid;
#include <lunaix/syscall.h>
-#define _SIG_NUM 8
+#define _SIG_NUM 16
#define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig)))
-#define _SIGSEGV 0
-#define _SIGALRM 1
-#define _SIGCHLD 2
+#define _SIGSEGV 1
+#define _SIGALRM 2
+#define _SIGCHLD 3
#define _SIGCLD _SIGCHLD
-#define _SIGINT 3
-#define _SIGKILL 4
-#define _SIGSTOP 5
-#define _SIGCONT 6
+#define _SIGINT 4
+#define _SIGKILL 5
+#define _SIGSTOP 6
+#define _SIGCONT 7
+#define _SIGTERM 8
#define __SIGNAL(num) (1 << (num))
-#define __SET_SIGNAL(bitmap, num) (bitmap = bitmap | __SIGNAL(num))
+#define __SIGSET(bitmap, num) (bitmap = bitmap | __SIGNAL(num))
+#define __SIGTEST(bitmap, num) (bitmap & __SIGNAL(num))
+#define __SIGCLEAR(bitmap, num) ((bitmap) = (bitmap) & ~__SIGNAL(num))
#define _SIGNAL_UNMASKABLE (__SIGNAL(_SIGKILL) | __SIGNAL(_SIGSTOP))
__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler);
+__LXSYSCALL3(int,
+ sigprocmask,
+ int,
+ how,
+ const sigset_t,
+ *set,
+ sigset_t,
+ *oldset);
+
#endif /* __LUNAIX_SIGNAL_H */
#define __SYSCALL_sigprocmask 12
#define __SYSCALL_signal 13
#define __SYSCALL_pause 14
+#define __SYSCALL_kill 15
#define __SYSCALL_MAX 0x100
#include <stdint.h>
-#define PROCTERM 0x10000
-#define PROCSTOP 0x20000
+#define PEXITTERM 0x100
+#define PEXITSTOP 0x200
+#define PEXITSIG 0x400
+
+#define PEXITNUM(flag, code) (flag | (code & 0xff))
#define WNOHANG 1
#define WUNTRACED 2
-#define WEXITSTATUS(wstatus) ((wstatus & 0xffff))
-#define WIFSTOPPED(wstatus) ((wstatus & PROCSTOP))
+#define WEXITSTATUS(wstatus) ((wstatus & 0xff))
+#define WIFSTOPPED(wstatus) ((wstatus & PEXITSTOP))
#define WIFEXITED(wstatus) \
- ((wstatus & PROCTERM) && ((short)WEXITSTATUS(wstatus) >= 0))
+ ((wstatus & PEXITTERM) && ((char)WEXITSTATUS(wstatus) >= 0))
+
+#define WIFSIGNALED(wstatus) ((wstatus & PEXITSIG))
+// TODO: WTERMSIG
typedef int32_t pid_t;
# 约定
# arg1: 目标进程PCB地址 (next
- popl %ecx # next
+ popl %ebx # next
movl __current, %eax
- movl 88(%eax), %ebx # __current->pagetable
- movl 88(%ecx), %eax # next->pagetable
+ movl 88(%eax), %ecx # __current->pagetable
+ movl 88(%ebx), %eax # next->pagetable
- cmpl %ebx, %eax # if(next->pagtable != __current->pagetable) {
+ cmpl %ecx, %eax # if(next->pagtable != __current->pagetable) {
jz 1f
movl %eax, %cr3 # cpu_lcr3(next->pagetable)
# }
1:
- movl %ecx, __current # __current = next
+ movl %ebx, __current # __current = next
# 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
# 需要使用一个临时的栈空间
jz 1f
jmp handle_signal
1:
- leal 8(%ecx), %eax
+ leal 8(%ebx), %eax
jmp soft_iret
.global handle_signal
#include <arch/x86/interrupts.h>
#include <lunaix/common.h>
+#include <lunaix/lxsignal.h>
#include <lunaix/mm/mm.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/region.h>
ptr,
param->cs,
param->eip);
- terminate_proc(LXSEGFAULT);
+ signal_send(__current->pid, _SIGSEGV);
+ schedule();
// should not reach
while (1)
;
.long __lxsys_sigprocmask
.long __lxsys_signal
.long __lxsys_pause
+ .long __lxsys_kill /* 15 */
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
.long 0
.eip = (void*)__proc0,
.ss = KDATA_SEG,
.eflags = cpu_reflags() };
+ proc0->parent = proc0;
// 方案1:必须在读取eflags之后禁用。否则当进程被调度时,中断依然是关闭的!
// cpu_disable_interrupt();
kprintf(KINFO "SIGCHLD received\n");
}
+void __USER__
+sigsegv_handler(int signum)
+{
+ pid_t pid = getpid();
+ kprintf(KWARN "SIGSEGV received on process %d\n", pid);
+ _exit(signum);
+}
+
void __USER__
_lxinit_main()
{
#endif
signal(_SIGCHLD, sigchild_handler);
+ signal(_SIGSEGV, sigsegv_handler);
int status;
#ifdef WAIT_DEMO
waitpid(-1, &status, WNOHANG);
- for (size_t i = 0; i < 10; i++) {
+ for (size_t i = 0; i < 5; i++) {
pid_t pid = 0;
if (!(pid = fork())) {
+ signal(_SIGSEGV, sigsegv_handler);
sleep(i);
if (i == 3) {
i = *(int*)0xdeadc0de; // seg fault!
while ((p = wait(&status)) >= 0) {
short code = WEXITSTATUS(status);
- if (WIFEXITED(status)) {
+ if (WIFSIGNALED(status)) {
+ kprintf(KINFO "Process %d terminated by signal, exit_code: %d\n",
+ p,
+ code);
+ } else if (WIFEXITED(status)) {
kprintf(KINFO "Process %d exited with code %d\n", p, code);
} else {
kprintf(KWARN "Process %d aborted with code %d\n", p, code);
void
run(struct proc_info* proc)
{
- if (!(__current->state & ~PROC_RUNNING)) {
- __current->state = PROC_STOPPED;
- }
proc->state = PROC_RUNNING;
/*
"jmp switch_to\n" ::"r"(proc)); // kernel/asm/x86/interrupt.S
}
+int
+can_schedule(struct proc_info* proc)
+{
+ if (__SIGTEST(proc->sig_pending, _SIGKILL)) {
+ // 如果进程受到SIGKILL,则直接终止,该进程不给予调度。
+ terminate_proc(PEXITNUM(PEXITSIG, _SIGKILL));
+ return 0;
+ } else if (__SIGTEST(proc->sig_pending, _SIGCONT)) {
+ __SIGCLEAR(proc->sig_pending, _SIGSTOP);
+ } else if (__SIGTEST(proc->sig_pending, _SIGSTOP)) {
+ // 如果进程受到SIGSTOP,则该进程不给予调度。
+ return 0;
+ }
+
+ return 1;
+}
+
void
schedule()
{
struct proc_info* next;
int prev_ptr = sched_ctx.procs_index;
int ptr = prev_ptr;
+
+ if (!(__current->state & ~PROC_RUNNING)) {
+ __current->state = PROC_STOPPED;
+ }
+
// round-robin scheduler
+redo:
do {
ptr = (ptr + 1) % sched_ctx.ptable_len;
next = &sched_ctx._procs[ptr];
sched_ctx.procs_index = ptr;
+ if (!can_schedule(next)) {
+ // 如果该进程不给予调度,则尝试重新选择
+ goto redo;
+ }
+
run(next);
}
__DEFINE_LXSYSCALL1(void, exit, int, status)
{
terminate_proc(status);
+ schedule();
}
__DEFINE_LXSYSCALL(void, yield)
{
if (!~wpid || proc->pid == wpid || proc->pgid == -wpid) {
if (proc->state == PROC_TERMNAT && !options) {
- status_flags |= PROCTERM;
+ status_flags |= PEXITTERM;
goto done;
}
if (proc->state == PROC_STOPPED && (options & WUNTRACED)) {
- status_flags |= PROCSTOP;
+ status_flags |= PEXITSTOP;
goto done;
}
}
done:
cpu_disable_interrupt();
- *status = (proc->exit_code & 0xffff) | status_flags;
+ status_flags |= PEXITSIG * (proc->sig_inprogress != 0);
+ *status = proc->exit_code | status_flags;
return destroy_process(proc->pid);
}
}
// every process is the child of first process (pid=1)
- if (process->parent) {
- llist_append(&process->parent->children, &process->siblings);
- } else {
- process->parent = &sched_ctx._procs[0];
+ if (!process->parent) {
+ process->parent = &sched_ctx._procs[1];
}
+ llist_append(&process->parent->children, &process->siblings);
+
process->state = PROC_STOPPED;
}
__current->state = PROC_TERMNAT;
__current->exit_code = exit_code;
- __SET_SIGNAL(__current->parent->sig_pending, _SIGCHLD);
-
- schedule();
+ __SIGSET(__current->parent->sig_pending, _SIGCHLD);
}
struct proc_info*
+#include <lunaix/lunistd.h>
+#include <lunaix/lxsignal.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
#include <lunaix/signal.h>
+#include <lunaix/spike.h>
#include <lunaix/status.h>
#include <lunaix/syscall.h>
extern struct scheduler sched_ctx; /* kernel/sched.c */
+void __USER__
+default_sighandler_term(int signum)
+{
+ _exit(signum);
+}
+
void* default_handlers[_SIG_NUM] = {
// TODO: 添加默认handler
+ [_SIGINT] = default_sighandler_term,
+ [_SIGTERM] = default_sighandler_term,
};
// Referenced in kernel/asm/x86/interrupt.S
void*
signal_dispatch()
{
- // if (!(SEL_RPL(__current->intr_ctx.cs))) {
- // // 同特权级间调度不进行信号处理
- // return 0;
- // }
-
if (!__current->sig_pending) {
// 没有待处理信号
return 0;
}
int sig_selected =
- 31 - __builtin_clz(__current->sig_pending & ~__current->sig_mask);
+ 31 - __builtin_clz(__current->sig_pending &
+ ~(__current->sig_mask | __current->sig_inprogress));
- __current->sig_pending = __current->sig_pending & ~__SIGNAL(sig_selected);
+ __SIGCLEAR(__current->sig_pending, sig_selected);
+
+ if (sig_selected == 0) {
+ // SIG0 is reserved
+ return 0;
+ }
if (!__current->sig_handler[sig_selected] &&
!default_handlers[sig_selected]) {
sig_ctx->signal_handler = default_handlers[sig_selected];
}
- __current->sig_mask |= __SIGNAL(sig_selected);
+ __SIGSET(__current->sig_inprogress, sig_selected);
return sig_ctx;
}
+int
+signal_send(pid_t pid, int signum)
+{
+ if (signum < 0 || signum >= _SIG_NUM) {
+ __current->k_status = LXINVL;
+ return -1;
+ }
+
+ struct proc_info* proc;
+ if (pid > 0) {
+ proc = get_process(pid);
+ goto send_single;
+ } else if (!pid) {
+ proc = __current;
+ goto send_grp;
+ } else if (pid < -1) {
+ proc = get_process(-pid);
+ goto send_grp;
+ } else {
+ // TODO: send to all process.
+ // But I don't want to support it yet.
+ __current->k_status = LXINVL;
+ return -1;
+ }
+
+send_grp:
+ struct proc_info *pos, *n;
+ llist_for_each(pos, n, &proc->grp_member, grp_member)
+ {
+ __SIGSET(pos->sig_pending, signum);
+ }
+ return 0;
+
+send_single:
+ if ((proc->state & PROC_TERMMASK)) {
+ __current->k_status = LXINVL;
+ return -1;
+ }
+ __SIGSET(proc->sig_pending, signum);
+ return 0;
+}
+
__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
{
__current->intr_ctx = sig_ctx->prev_context;
- __current->sig_mask &= ~__SIGNAL(sig_ctx->sig_num);
__current->flags &= ~PROC_FINPAUSE;
+ __SIGCLEAR(__current->sig_inprogress, sig_ctx->sig_num);
schedule();
}
__DEFINE_LXSYSCALL2(int, signal, int, signum, sighandler_t, handler)
{
- if (signum < 0 || signum >= _SIG_NUM) {
+ if (signum <= 0 || signum >= _SIG_NUM) {
return -1;
}
- if (((1 << signum) & _SIGNAL_UNMASKABLE)) {
+ if ((__SIGNAL(signum) & _SIGNAL_UNMASKABLE)) {
return -1;
}
})
__current->k_status = EINTR;
return -1;
+}
+
+__DEFINE_LXSYSCALL2(int, kill, pid_t, pid, int, signum)
+{
+ return signal_send(pid, signum);
}
\ No newline at end of file