信号量
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_handlerSIG_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文件系统的实现
内核级线程
终极项目 更改内核进程调度函数,进行内核调度函数的自动适配