Linux内核中的信号机制??信号处理
作者:网络转载 发布时间:[ 2013/2/25 10:12:12 ] 推荐标签:
get_sigframe()通过用户态空间堆栈的sp-sizeof(struct sigframe)在用户态堆栈的顶部分配了一篇存储空间,将来使用完成后,再通过sp+sizeof(struct sigframe)还原。
通过上面的讨论,我们再回到do_signal()中来,如果有用户态的信号处理函数,do_signal()会调用handle_signal(),handle_signal()将调用setup_frame()或者setup_rt_frame()来完成实际的工作,这里我们以setup_frame()为例进行进一步讨论。
static int
setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
{
//在用户态堆栈上分配一个sigframe结构
struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
int err = 0;
if (!frame)
return 1;
//把相关信息从内核态备份到用户态堆栈的sigframe结构中
err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);
if (_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
if (err == 0)
err = setup_return(regs, ka, &frame->retcode, frame, usig);
return err;
}
setup_return()设置返回地址,其定义如下:
static int
setup_return(struct pt_regs *regs, struct k_sigaction *ka,
unsigned long __user *rc, void __user *frame, int usig)
{
unsigned long handler = (unsigned long)ka->sa.sa_handler;
unsigned long retcode;
int thumb = 0;
unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;
/*
* Maybe we need to deliver a 32-bit signal to a 26-bit task.
*/
if (ka->sa.sa_flags & SA_THIRTYTWO)
cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
#ifdef CONFIG_ARM_THUMB
if (elf_hwcap & HWCAP_THUMB) {
/*
* The LSB of the handler determines if we're going to
* be using THUMB or ARM mode for this signal handler.
*/
thumb = handler & 1;
if (thumb)
cpsr |= PSR_T_BIT;
else
cpsr &= ~PSR_T_BIT;
}
#endif
<SPAN style="WHITE-SPACE: pre"> </SPAN>//这里的retcode是保存手工构造的sigreturn()代码
if (ka->sa.sa_flags & SA_RESTORER) {
retcode = (unsigned long)ka->sa.sa_restorer;
} else {
unsigned int idx = thumb;
if (ka->sa.sa_flags & SA_SIGINFO)
idx += 2;
if (__put_user(sigreturn_codes[idx], rc))
return 1;
if (cpsr & MODE32_BIT) {
/*
* 32-bit code can use the new high-page
* signal return code support.
*/
retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
} else {
/*
* Ensure that the instruction cache sees
* the return code written onto the stack.
*/
flush_icache_range((unsigned long)rc,
(unsigned long)(rc + 1));
retcode = ((unsigned long)rc) + thumb;
}
}
regs->ARM_r0 = usig;
regs->ARM_sp = (unsigned long)frame;//堆栈
regs->ARM_lr = retcode;//返回地址,当用户态信号处理函数结束时,会把这个地址作为返回地址
regs->ARM_pc = handler;//信号处理函数
regs->ARM_cpsr = cpsr;
return 0;
}
当setup_frame()返回后,一切准备绪,因此可以从内核态返回了,这样顺利过渡到用户态的信号处理函数。当这个函数处理结束后,会通过retcode再次进入内核态,现在我们看看retcode是如何处理的,下面的代码选自glibc(2.3.2):
#include <sysdep.h>
/* If no SA_RESTORER function was specified by the application we use
one of these. This avoids the need for the kernel to synthesise a return
instruction on the stack, which would involve expensive cache flushes. */
ENTRY(__default_sa_restorer)
swi SYS_ify(sigreturn)
#ifdef __NR_rt_sigreturn
ENTRY(__default_rt_sa_restorer)
swi SYS_ify(rt_sigreturn)
#define SYS_ify(syscall_name) (__NR_##syscall_name)
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11