linux0.11信号处理程序阅读注释笔记
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
[ 1] linux0.11引导程序阅读注释。
[ 2] linux0.11由实模式进入保护模式程序阅读注释 。
[ 3] linux0.11护模式初始化程序阅读注释。
[ 4] linux0.11主存管理程序阅读注释。
[ 5] linux0.11中断/异常机制初始设置相关程序阅读注释。
[ 6] linux0.11缓冲区管理程序阅读注释。
[ 7] linux0.11文件系统管理程序阅读注释。
[ 8] linux0.11块设备驱动及访问请求管理程序阅读注释。
[ 9] linux0.11字符设备驱动及访问请求管理程序阅读注释。
[10] linux0.11多任务管理程序阅读注释。
篇幅较长,可通过浏览器的搜索功能(Ctrl + f)搜索函数名了解相应函数的实现机制,如 do_signal。
[11] linux0.11信号处理程序阅读注释
下次将关注linux0.11的剩余代码以及构建 linux0.11映像文件的相关代码,再随缘更改下以往注释的措辞和文笔。
signal.c
/*
* linux/kernel/signal.c
*
* (C) 1991 Linus Torvalds
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <signal.h>
volatile void do_exit(int error_code);
/* sys_sgetmask,
* 获取当前进程信号屏蔽码。*/
int sys_sgetmask()
{
return current->blocked;
}
/* sys_ssetmask,
* 设置当前进程信号屏蔽码,返回旧信号屏蔽码。*/
int sys_ssetmask(int newmask)
{
int old=current->blocked;
/* SIGKILL不可屏蔽 */
current->blocked = newmask & ~(1<<(SIGKILL-1));
return old;
}
/* save_old,
* 将from所指内核内存中(struct sigaction)类型信息拷贝
* 到to所指用户内存中。*/
static inline void save_old(char * from,char * to)
{
int i;
verify_area(to, sizeof(struct sigaction));
for (i=0 ; i< sizeof(struct sigaction) ; i++) {
put_fs_byte(*from,to);
from++;
to++;
}
}
/* get_new,
* 将from所指用户内存段中的(struct sigaction)类型信息
* 拷贝到to所指向的内核内存段中。*/
static inline void get_new(char * from,char * to)
{
int i;
for (i=0 ; i< sizeof(struct sigaction) ; i++)
*(to++) = get_fs_byte(from++);
}
/* sys_signal,sys_sigaction是用户程序设置信号处理函数的两
* 种方式,分别对应于OS所提供的signal()和sigaction系统调用。*/
/* sys_signal,
* 设置当前进程signum信号的处理结构体(含信号处理函数)。*/
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;
/* 见do_signal */
tmp.sa_restorer = (void (*)(void)) restorer;
/* 原信号处理函数地址 */
handler = (long) current->sigaction[signum-1].sa_handler;
/* 设置进程signum信号处理函数 */
current->sigaction[signum-1] = tmp;
return handler;
}
/* sys_sigaction,
* 获取signum信号原处理信息,设置signum信号的处理信息。*/
int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
struct sigaction tmp;
if (signum<1 || signum>32 || signum==SIGKILL)
return -1;
/* 将action设置到signum信号处理结构体中,并
* 将signum信号原处理结构体拷贝到出参中。*/
tmp = current->sigaction[signum-1];
get_new((char *) action,
(char *) (signum-1+current->sigaction));
if (oldaction)
save_old((char *) &tmp,(char *) oldaction);
/* 若无SA_NOMASK则置屏蔽signum信号位 */
if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
current->sigaction[signum-1].sa_mask = 0;
else
current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
return 0;
}
/* do_signal,
* 信号处理C程序。
*
* 由 ret_from_sys_call 调用(系统调用等结束后将跳转ret_from_sys_call)。
* ss esp eflags cs eip由用户程序在系统调用时CPU入栈;ds es fs edx ecx
* ebx eax为系统调用入口处理程序_system_call入栈;signr在ret_from_sys_call
* 程序段中入栈,为需处理的信号。*/
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; /* 系统调用时用户程序中的eip */
/* 获取当前进程信号处理结构体 */
struct sigaction * sa = current->sigaction + signr - 1;
int longs;
unsigned long * tmp_esp;
/* 信号处理函数,1-不处理即忽略信号,0-默认方式处理信号。*/
sa_handler = (unsigned long) sa->sa_handler;
if (sa_handler==1)
return;
if (!sa_handler) {
if (signr==SIGCHLD)
return;
/* 对于非来自子进程的信号则调用do_exit处理该信号 */
else
do_exit(1<<(signr-1));
}
/* 若用户程序曾设置过信号处理函数于sa_handler,
* 则调用用户设置的信号处理函数处理信号。*/
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
/* 将信号处理函数地址写入eip寄存器所在栈内存中,以在系
* 统调用返回时(IRET)执行用户程序所指定的信号处理函数。*/
*(&eip) = sa_handler;
/* 在用户栈中写入以下值是为了在执行完用户所设置信号处理
* 函数后执行sa_restorer函数且再执行系统调用后续语句。*/
longs = (sa->sa_flags & SA_NOMASK)?7:8;
/* 将用户栈顶向下移以留出longs个元素位置 */
*(&esp) -= longs;
/* 写时拷贝用户程序栈顶所对应内存页 */
verify_area(esp,longs*4);
tmp_esp=esp;
/* 将sa_restorer函数及其所需参数压入栈顶 */
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++);
/* 在sa_restorer处理函数中执行return指令时将弹
* 出old_eip给eip即继续执行系统调用后续语句。*/
put_fs_long(old_eip,tmp_esp++);
/* 设定当前进程将被屏蔽的信号 */
current->blocked |= sa->sa_mask;
/* 将内核扩展用户栈顶所压入各参数粗略介绍下。
* |-----------|
* |old_eip |
* |-----------|
* |eflags |
* |-----------|
* |edx |
* |-----------|
* |ecx |
* |-----------|
* |eax |
* |-----------|
* |(blocked) |
* |-----------|
* |signr |
* |-----------|
* |sa_restorer|
* |-----------|
* 由于在do_signal函数中将eip所在栈内存中的值
* 更改为信号处理函数地址, 当do_signal返回到
* ret_from_sys_call 由ret_from_sys_call 执行
* IRET恢复系统调用现场时将跳转执行信号处理函
* 数,信号处理函数执行RET指令时会将栈顶的函数
* 地址sa_restorer弹出到eip寄存器(局部RET),该
* 函数将会处理并回收栈中signr-eflags参数, 待
* sa_restorer执行RET后会弹出栈顶old_eip给eip
* 从而执行用户程序中发生系统调用处的后续语句。*/
}
/* 好久没读到这么短的程序模块了^_^。
* 虽然还有值得被挖掘的内容未被此文进一步挖掘,
* 但就以这样的方式结束也让此文较满足和开心呢。*/
signal.h
#ifndef _SIGNAL_H
#define _SIGNAL_H
#include <sys/types.h>
typedef int sig_atomic_t;
typedef unsigned int sigset_t; /* 32 bits */
#define _NSIG 32
#define NSIG _NSIG /* 信号种类 */
/* 粗略领略进程各种信号 */
#define SIGHUP 1 /* 进程终止信号 */
#define SIGINT 2 /* 键盘中断信号 */
#define SIGQUIT 3 /* 键盘退出信号 */
#define SIGILL 4 /* 非法指令信号 */
#define SIGTRAP 5 /* 断点跟踪信号 */
#define SIGABRT 6 /* 异常结束信号 */
#define SIGIOT 6 /* 同SIGABRT */
#define SIGUNUSED 7 /* 保留未用 */
#define SIGFPE 8 /* 协处理器出错信号 */
#define SIGKILL 9 /* 强迫进程终止信号 */
#define SIGUSR1 10 /* 用户信号1 */
#define SIGSEGV 11 /* 非法访问内存信号 */
#define SIGUSR2 12 /* 用户信号2 */
#define SIGPIPE 13 /* 管道写错误信号 */
#define SIGALRM 14 /* 超时报警信号 */
#define SIGTERM 15 /* 进程终止信号 */
#define SIGSTKFLT 16 /* 协处理器栈出错信号 */
#define SIGCHLD 17 /* 子进程运行结束或被终止 */
#define SIGCONT 18 /* 恢复进程继续执行信号 */
#define SIGSTOP 19 /* 暂停进程的执行信号 */
#define SIGTSTP 20 /* 来自tty的进程停止信号 */
#define SIGTTIN 21 /* 后台进程请求输入信号 */
#define SIGTTOU 22 /* 后台进程请求输出信号 */
/* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */
#define SA_NOCLDSTOP 1 /* 若子进程处于停止状态则不处理SIGCHLD */
#define SA_NOMASK 0x40000000 /* 在用户设定的信号处理函数中可再收该信号 */
#define SA_ONESHOT 0x80000000 /* 信号处理函数指针一旦被调用过就恢复到默认值0 */
#define SIG_BLOCK 0 /* for blocking signals */
#define SIG_UNBLOCK 1 /* for unblocking signals */
#define SIG_SETMASK 2 /* for setting the signal mask */
/* 信号处理函数 */
#define SIG_DFL ((void (*)(int))0) /* default signal handling */
#define SIG_IGN ((void (*)(int))1) /* ignore signal */
/* struct sigaction,
* 信号处理结构体类型。*/
struct sigaction {
void (*sa_handler)(int); /* 信号处理函数指针 */
sigset_t sa_mask; /* 信号屏蔽位 */
int sa_flags; /* 信号处理标志(SA_NOMASK etc.) */
void (*sa_restorer)(void); /* 信号恢复用户现场函数指针 */
};
void (*signal(int _sig, void (*_func)(int)))(int);
int raise(int sig);
int kill(pid_t pid, int sig);
int sigaddset(sigset_t *mask, int signo);
int sigdelset(sigset_t *mask, int signo);
int sigemptyset(sigset_t *mask);
int sigfillset(sigset_t *mask);
int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */
int sigpending(sigset_t *set);
int sigprocmask(int how, sigset_t *set, sigset_t *oldset);
int sigsuspend(sigset_t *sigmask);
int sigaction(int sig, struct sigaction *act, struct sigaction *oldact);
#endif /* _SIGNAL_H */
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e
added ecosystem file for PM2 4 年前
5def40a3
Add host customization support for the NodeJS version 4 年前
更多推荐
已为社区贡献9条内容
所有评论(0)