信号学习心得 如何模拟发信号给进程

系统调用
SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset,
		sigset_t __user *, oset, size_t, sigsetsize) //堵塞或者撤销堵塞某些信号
	=>sigprocmask 
SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,
		old_sigset_t __user *, oset)
	=>sigaddsetmask(&new_blocked, new_set);

SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)//设置信号处理函数
	=>do_sigaction(sig, &new_sa, &old_sa);

内核信号触发,详见LINUX内存管理部分,do_page_fault

内核信号处理
do_notify_resume
	=>do_signal
		=>signr = get_signal_to_deliver(&info, &ka, regs, NULL);
			=>for (;;)
				=>signr = dequeue_signal(current, ¤t->blocked, info);//pending队列取一个信号
				=>if (!signr)//队列为空时退出
					break; /* will return 0 */
				=>if (ka->sa.sa_handler != SIG_DFL) {//如果不是默认信号处理函数则退出
						/* Run the handler.  */
						*return_ka = *ka;
			
						if (ka->sa.sa_flags & SA_ONESHOT)
							ka->sa.sa_handler = SIG_DFL;
			
						break; /* will return non-zero "signr" value */
					}
				=>if (sig_kernel_coredump(signr))//如果信号比较严重,则coredump,增加调试信息
					do_coredump(info->si_signo, info->si_signo, regs);
						=>retval = binfmt->core_dump(&cprm);
							static struct linux_binfmt elf_format = {
								.module		= THIS_MODULE,
								.load_binary	= load_elf_binary,
								.load_shlib	= load_elf_library,
								.core_dump	= elf_core_dump,
								.min_coredump	= ELF_EXEC_PAGESIZE,
							};
							#ifdef CONFIG_ELF_CORE
							static int elf_core_dump(struct coredump_params *cprm);
							#else
							#define elf_core_dump	NULL
							#endif
				=>do_group_exit(info->si_signo);
		=>handle_signal(signr, &info, &ka, oldset, regs)
			=>ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset, ka, regs, sig, oldset, info);
					=>setup_rt_frame //arch\mips\kernel):	.setup_rt_frame	= setup_rt_frame,
						=>frame = get_sigframe(ka, regs, sizeof(*frame));
						=>/* Create siginfo.  */
						err |= copy_siginfo_to_user(&frame->rs_info, info);//设置信号处理函数栈帧
						=>regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;//挂接信号处理函数,handle_signal返回时调用sa_handler

内核在允许进程恢复用户态执行之前,检测进程TIF_SIGPENDING标志的数值,每当内核处理完1个中断/异常时,就检查是否存在进程挂起信号
例子如下:

ret_from_exception
	=>movl TI_flags(%ebp), %ecx
	=>andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
					# int/exception return?
	=>jne work_pending
		=>testb $_TIF_NEED_RESCHED, %cl
		=>jz work_notifysig
			=>xorl %edx, %edx
			=>call do_notify_resume
				=>if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
					do_signal(regs);
				=>clear_thread_flag(TIF_IRET);
			=>jmp resume_userspace_sig

监控进程:可以通过epoll与所有进程通信,一旦通信是吧,可以调用waitpid获取状态

void do_notify_resume(struct pt_regs *regs, void *_unused,
		      __u32 thread_info_flags)
{
	/* Pending single-step? */
	if (thread_info_flags & _TIF_SINGLESTEP) {
		regs->eflags |= TF_MASK;
		clear_thread_flag(TIF_SINGLESTEP);
	}

	/* deal with pending signal delivery */
	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
		do_signal(regs);
			=>handle_signal(signr, &info, &ka, oldset, regs)
				=>ret = setup_frame(sig, ka, oldset, regs);
					=>printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->eip, frame->pretcode);
	
	clear_thread_flag(TIF_IRET);
}

文章参考
Linux信号(signal) 机制分析
http://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html

如何模拟发信号给进程
https://www.cnblogs.com/itech/archive/2012/03/05/2380794.html

利用sigpending,sigismember检测信号是否被挂起
http://blog.csdn.net/he_0123/article/details/46584971
该篇文章讲SIGINT替换成SIGILL,然后将main函数的主体增加while {sleep(1);} ;做实验kill -ILL 进程号,内核会进入do_signal函数

Linux Signal实现代码分析
https://blog.csdn.net/walkingman321/article/details/6167435

你可能感兴趣的:(linux,device,driver,linux内核,汇编语言)