linux内核笔记四 信号

这篇博客探讨了操作系统中的信号量概念,包括常见的信号如SIGHUP、SIGINT等,并详细解析了系统调用过程中的信号处理。在接收到信号后,系统通过do_signal函数进行处理,检查信号句柄,若为忽略或默认处理则不作响应,否则执行相应的处理程序。文章还展示了系统调用的流程和信号量在进程调度中的作用。
摘要由CSDN通过智能技术生成

信号量

1、SIGHUP
SIGINT
SIGQUIT
SIGILL
SIGTRAP
SIGPIPE
SIGCHLD
SIFTTOU
等等

/include/signal.h

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGUNUSED	 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22

信号关注焦点

1、在系统中什么是信号 都有什么信号

信号 signal 信号量 sigaction

信号也是一种系统调用

_system_call:
	cmpl $nr_system_calls-1,%eax
	ja bad_sys_call
	push %ds
	push %es
	push %fs
	pushl %edx
	pushl %ecx		# push %ebx,%ecx,%edx as parameters
	pushl %ebx		# to the system call
	movl $0x10,%edx		# set up ds,es to kernel space
	mov %dx,%ds
	mov %dx,%es
	movl $0x17,%edx		# fs points to local data space
	mov %dx,%fs
	call _sys_call_table(,%eax,4)
	pushl %eax
	movl _current,%eax
	cmpl $0,state(%eax)		# state
	jne reschedule
	cmpl $0,counter(%eax)		# counter
	je reschedule
ret_from_sys_call:
	movl _current,%eax		# task[0] cannot have signals
	cmpl _task,%eax
	je 3f
	cmpw $0x0f,CS(%esp)		# was old code segment supervisor ?
	jne 3f
	cmpw $0x17,OLDSS(%esp)		# was stack segment = 0x17 ?
	jne 3f
	movl signal(%eax),%ebx
	movl blocked(%eax),%ecx
	notl %ecx
	andl %ebx,%ecx
	bsfl %ecx,%ecx
	je 3f
	btrl %ecx,%ebx
	movl %ebx,signal(%eax)
	incl %ecx
	pushl %ecx
	call _do_signal
	popl %eax
3:	popl %eax
	popl %ebx
	popl %ecx
	popl %edx
	pop %fs
	pop %es
	pop %ds
	iret

看一下一会看到有个do_signal
然后前面有一系列操作

我们就从这里切进去。

do_signal

void do_signal(long signr,long eax, long ebx, long ecx, long edx,
	long fs, long es, long ds,
	long eip, long cs, long eflags,
	unsigned long * esp, long ss)  //乱七八糟传一堆东西
{
	unsigned long sa_handler;
	long old_eip=eip;
	struct sigaction * sa = current->sigaction + signr - 1;
	int longs;
	unsigned long * tmp_esp;

	sa_handler = (unsigned long) sa->sa_handler;  //指到当前信号处。
	if (sa_handler==SIG_IGN)   //在信号列表
								//如果信号句柄为可忽略信号 就忽略
		return;
	if (sa_handler==SIG_DFL) {   //如果信号为默认处理的  信号量为SIGCHLD就返回 不然就终止运行
		if (signr==SIGCHLD)
			return;
		else
			do_exit(1<<(signr-1));
	}
	if (sa->sa_flags & SA_ONESHOT)
		sa->sa_handler = NULL;
	*(&eip) = sa_handler;
	longs = (sa->sa_flags & SA_NOMASK)?7:8;
	*(&esp) -= longs;
	verify_area(esp,longs*4);
	tmp_esp=esp;
	put_fs_long((long) sa->sa_restorer,tmp_esp++);
	put_fs_long(signr,tmp_esp++);
	if (!(sa->sa_flags & SA_NOMASK))
		put_fs_long(current->blocked,tmp_esp++);
	put_fs_long(eax,tmp_esp++);
	put_fs_long(ecx,tmp_esp++);
	put_fs_long(edx,tmp_esp++);
	put_fs_long(eflags,tmp_esp++);
	put_fs_long(old_eip,tmp_esp++);
	current->blocked |= sa->sa_mask;
}
do_signal 是系统调用中断处理程序中的信号处理程序。

来了信号量的结构体。

struct sigaction * sa = current->sigaction + signr - 1; //找到信号结构体
sa_handler = (unsigned long) sa->sa_handler; //去除信号句柄
if (sa_handlerSIG_IGN) //在信号列表
//如果信号句柄为可忽略信号 就忽略
return;
if (sa_handler
SIG_DFL) { //如果信号为默认处理的 信号量为SIGCHLD就返回 不然就终止运行
if (signr==SIGCHLD)
return;
else
do_exit(1<<(signr-1));
}

如果信号句柄为可忽略 则不处理直接返回
如果信号句柄为默认处理,如果是通知其子进程结束信号,则直接返回
如果不是,直接终止进程执行

if (sa->sa_flags & SA_ONESHOT)
		sa->sa_handler = NULL;   //如果信号句柄只使用一次 则将句柄置空
*(&eip) = sa_handler;
longs = (sa->sa_flags & SA_NOMASK)?7:8;
*(&esp) -= longs;
verify_area(esp,longs*4);
tmp_esp=esp;
put_fs_long((long) sa->sa_restorer,tmp_esp++);
put_fs_long(signr,tmp_esp++);
if (!(sa->sa_flags & SA_NOMASK))
	put_fs_long(current->blocked,tmp_esp++);
put_fs_long(eax,tmp_esp++);
put_fs_long(ecx,tmp_esp++);
put_fs_long(edx,tmp_esp++);
put_fs_long(eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
current->blocked |= sa->sa_mask;

用户程序
系统调用

系统调用的处理程序
对信号识别的预处理
调用do_dignal函数,将对应的信号处理程序句柄插入到用户的堆栈中。
在这里插入图片描述

在这里插入图片描述

2、在系统中接受到信号后,它是如何处理的

我们回到system_call.s

_system_call:
	cmpl $nr_system_calls-1,%eax
	ja bad_sys_call
	push %ds
	push %es
	push %fs
	pushl %edx
	pushl %ecx		# push %ebx,%ecx,%edx as parameters
	pushl %ebx		# to the system call
	movl $0x10,%edx		# set up ds,es to kernel space
	mov %dx,%ds
	mov %dx,%es
	movl $0x17,%edx		# fs points to local data space
	mov %dx,%fs
	call _sys_call_table(,%eax,4)
	pushl %eax
	movl _current,%eax
	cmpl $0,state(%eax)		# state
	jne reschedule
	cmpl $0,counter(%eax)		# counter
	je reschedule
ret_from_sys_call:
	movl _current,%eax		# task[0] cannot have signals
	cmpl _task,%eax
	je 3f
	cmpw $0x0f,CS(%esp)		# was old code segment supervisor ?
	jne 3f
	cmpw $0x17,OLDSS(%esp)		# was stack segment = 0x17 ?
	jne 3f
	movl signal(%eax),%ebx
	movl blocked(%eax),%ecx
	notl %ecx
	andl %ebx,%ecx
	bsfl %ecx,%ecx
	je 3f
	btrl %ecx,%ebx
	movl %ebx,signal(%eax)
	incl %ecx
	pushl %ecx
	call _do_signal
	popl %eax
3:	popl %eax
	popl %ebx
	popl %ecx
	popl %edx
	pop %fs
	pop %es
	pop %ds
	iret

首先中断之后会去找系统调用表,call _sys_call_table。
找到了我们的sys_signal

int sys_signal(int signum, long handler, long restorer)
{
	struct sigaction tmp;

	if (signum<1 || signum>32 || signum==SIGKILL)
		return -1;    //信号范围错误就返回了
	tmp.sa_handler = (void (*)(int)) handler;
	tmp.sa_mask = 0;
	tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
	tmp.sa_restorer = (void (*)(void)) restorer;   //开始疯狂设置
	handler = (long) current->sigaction[signum-1].sa_handler;
	current->sigaction[signum-1] = tmp;   信息存到当前的sigaction中
	return handler;
}

里面也是sigaction结构体。
这个结构体里面有啥东西

struct sigaction {
	void (*sa_handler)(int);  //句柄  处理函数
	sigset_t sa_mask;  //掩码   阻塞非阻塞  阻塞了就不能执行其他东西
	int sa_flags;   //状态   一次信号还是多次信号等等
	void (*sa_restorer)(void);   //恢复函数  恢复系统调用之后的寄存器的值 设置啥的
};

1、设置分配一个信号结构体
2、检索信号范围要在1-32并且不是终止信号
3、指定信号处理句柄 调用这个函数的时候传入的参数
4、设置屏蔽码
5、设置该信号的状态只可执行一次就恢复到默认值
6、保存恢复处理程序指针
7、更新当前标志指针的信号信息

所以do_signal就是做了信号的预处理与设置

最后就执行do_signal。

一般项目具体内容

操作系统的引导
系统调用
进程运行轨迹的跟踪与统计
信号量的实现和应用
地址映射与 共享
字符显示的控制
proc文件系统的实现
内核级线程
终极项目 更改内核进程调度函数,进行内核调度函数的自动适配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值