feat: signal demo.
#ifndef __LUNAIX_SIGNAL_H
#define __LUNAIX_SIGNAL_H
+#include <lunaix/syscall.h>
+
#define _SIG_NUM 8
#define _SIG_PENDING(bitmap, sig) ((bitmap) & (1 << (sig)))
#define _SIGSEGV 0
#define _SIGALRM 1
#define _SIGCHLD 2
-#define _SIGCLD SIGCHLD
+#define _SIGCLD _SIGCHLD
#define _SIGINT 3
#define _SIGKILL 4
#define _SIGSTOP 5
#define _SIGCONT 6
-#define _SIGNAL_UNMASKABLE ((1 << _SIGKILL) | (1 << _SIGSTOP))
+#define __SIGNAL(num) (1 << (num))
+#define __SET_SIGNAL(bitmap, num) (bitmap = bitmap | __SIGNAL(num))
+
+#define _SIGNAL_UNMASKABLE (__SIGNAL(_SIGKILL) | __SIGNAL(_SIGSTOP))
#define _SIG_BLOCK 1
#define _SIG_UNBLOCK 2
typedef unsigned int sigset_t;
typedef void (*sighandler_t)(int);
+__LXSYSCALL2(int, signal, int, signum, sighandler_t, handler);
+
#endif /* __LUNAIX_SIGNAL_H */
// 获取v最近的最小k倍数
#define ROUNDDOWN(v, k) ((v) & ~((k)-1))
-#define __USER__ __attribute__((section("usrtext")))
+#define __USER__ __attribute__((section(".usrtext")))
inline static void
spin()
.skip 16
#endif
+.section .bss
+ .align 16
+ lo_tmp_stack:
+ .skip 128
+ tmp_stack:
+
.section .text
isr_template FAULT_DIVISION_ERROR
isr_template FAULT_GENERAL_PROTECTION, no_error_code=0
addl $8, %esp
-#ifdef __ASM_INTR_DIAGNOSIS
pushl %eax
+#ifdef __ASM_INTR_DIAGNOSIS
movl 4(%esp), %eax
movl %eax, debug_resv
- popl %eax
#endif
+ # 处理TSS.ESP的一些边界条件。如果是正常iret(即从内核模式*优雅地*退出)
+ # 那么TSS.ESP0应该为iret进行弹栈后,%esp的值。
+ # 所以这里的边界条件是:如返回用户模式,iret会额外弹出8个字节(ss,esp)
+ movl 8(%esp), %eax
+ andl $3, %eax
+ setnz %al
+ shll $3, %eax
+ addl $16, %eax
+ addl %esp, %eax
+ movl %eax, (_tss + 4)
+ popl %eax
iret
.global switch_to
switch_to:
# 约定
- # arg1: 目标进程PCB地址 (next)
- popl %ecx # next
-
- call signal_dispatch # kernel/signal.c
- movl %eax, %edx
+ # arg1: 目标进程PCB地址 (next
+ popl %ecx # next
movl __current, %eax
movl 88(%eax), %ebx # __current->pagetable
movl 88(%ecx), %eax # next->pagetable
1:
movl %ecx, __current # __current = next
- test %edx, %edx # do we have signal to handle?
+ # 我们已经处在了新的地址空间,为了避免影响其先前的栈布局
+ # 需要使用一个临时的栈空间
+ movl $tmp_stack, %esp
+ call signal_dispatch # kernel/signal.c
+
+ test %eax, %eax # do we have signal to handle?
jz 1f
- movl %edx, %eax
jmp handle_signal
1:
leal 8(%ecx), %eax
# 注意2:handle_signal在调用之前,须确保proc_sig已经写入用户栈!
leal 8(%eax), %ebx # arg1 in %eax: addr of proc_sig structure in user stack
- pushl 72(%ebx) # proc_sig->prev_context.ss
+ pushl $UDATA_SEG # proc_sig->prev_context.ss
pushl %eax # esp
pushl 64(%ebx) # proc_sig->prev_context.eflags
pushl $UCODE_SEG # cs
#include <arch/x86/interrupts.h>
+#include <arch/x86/tss.h>
#include <hal/apic.h>
#include <hal/cpu.h>
#include <lunaix/mm/page.h>
#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/proc.h>
+#include <lunaix/signal.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
#include <lunaix/timer.h>
#define WAIT_DEMO
#define IN_USER_MODE
+void __USER__
+sigchild_handler(int signum)
+{
+ kprintf(KINFO "SIGCHLD received\n");
+}
+
void __USER__
_lxinit_main()
{
}
#endif
+ signal(_SIGCHLD, sigchild_handler);
+
int status;
#ifdef WAIT_DEMO
// 测试wait
waitpid(-1, &status, WNOHANG);
- for (size_t i = 0; i < 5; i++) {
+ for (size_t i = 0; i < 10; i++) {
pid_t pid = 0;
if (!(pid = fork())) {
sleep(i);
}
proc->state = PROC_RUNNING;
- // XXX: 我们需要这一步吗?
- // tss_update_esp(__current->intr_ctx.esp);
+ /*
+ 将tss.esp0设置为上次调度前的esp值。
+ 当处理信号时,上下文信息是不会恢复的,而是保存在用户栈中,然后直接跳转进位于用户空间的sig_wrapper进行
+ 信号的处理。当用户自定义的信号处理函数返回时,sigreturn的系统调用才开始进行上下文的恢复(或者说是进行
+ 另一次调度。
+ 由于这中间没有进行地址空间的交换,所以第二次跳转使用的是同一个内核栈,而之前默认tss.esp0的值是永远指向最顶部
+ 这样一来就有可能会覆盖更早的上下文信息(比如嵌套的信号捕获函数)
+ */
+ tss_update_esp(proc->intr_ctx.registers.esp);
apic_done_servicing();
__current->state = PROC_TERMNAT;
__current->exit_code = exit_code;
+ __SET_SIGNAL(__current->parent->sig_pending, _SIGCHLD);
+
schedule();
}
int sig_selected =
31 - __builtin_clz(__current->sig_pending & ~__current->sig_mask);
- __current->sig_pending = __current->sig_pending & ~(1 << sig_selected);
+ __current->sig_pending = __current->sig_pending & ~__SIGNAL(sig_selected);
if (!__current->sig_handler[sig_selected] &&
!default_handlers[sig_selected]) {
return 0;
}
- uintptr_t ustack = __current->ustack_top;
+ uintptr_t ustack = __current->ustack_top & ~0xf;
if ((int)(ustack - USTACK_END) < (int)sizeof(struct proc_sig)) {
// 用户栈没有空间存放信号上下文
sig_ctx->signal_handler = default_handlers[sig_selected];
}
+ __current->sig_mask |= __SIGNAL(sig_selected);
+
return sig_ctx;
}
__DEFINE_LXSYSCALL1(int, sigreturn, struct proc_sig, *sig_ctx)
{
__current->intr_ctx = sig_ctx->prev_context;
+ __current->sig_mask &= ~__SIGNAL(sig_ctx->sig_num);
schedule();
}