日期:2014-05-16 浏览次数:20851 次
1. 前言
信号是类UNIX系统中一个重要的进程控制方法,向中断一样,可通过向进程发送不同的信号临时中断
程序的正常运行而进入信号处理程序或执行缺省的信号响应,如重新更新程序配置、终止进程等。
在用户空间中,信号处理接口是通过一系列系统调用来实现的,包括signal, sigaction,
sigsuspend, sigaltstack等,进程可通过以上这些接口定义进程的信号处理函数。如果要向其他进
程发信号,可通过kill系统调用实现。
在内核中对信号的处理程序主要定义在 kernel/signal.c, arch/***/kernel/signal.c等文件中,头
文件在 include/linux/signal.h, include/asm/signal.h等。
以下内核代码版本为2.6.19.2。
2. 数据结构
2.1 信号自身基本定义
用于定义信号处理
/* include/asm-generic/signal.h */
// 信号处理函数格式
typedef void __signalfn_t(int);
typedef __signalfn_t __user *__sighandler_t;
// 信号恢复函数
typedef void __restorefn_t(void);
typedef __restorefn_t __user *__sigrestore_t;
// 三个预定义的信号处理函数值
#define SIG_DFL ((__force __sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__force __sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__force __sighandler_t)-1) /* error return from signal */
/* include/asm-i386/signal.h */
#define _NSIG 64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
typedef unsigned long old_sigset_t; /* at least 32 bits */
// 信号集, 最多64个信号
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
// 老的信号处理结构
struct old_sigaction {
__sighandler_t sa_handler;
old_sigset_t sa_mask;
unsigned long sa_flags;
__sigrestore_t sa_restorer;
};
// 信号处理结构
struct sigaction {
// 信号处理函数
__sighandler_t sa_handler;
// 标志
unsigned long sa_flags;
// 信号恢复函数
__sigrestore_t sa_restorer;
// 信号集
sigset_t sa_mask; /* mask last for extensibility */
};
// 另一个定义
struct k_sigaction {
struct sigaction sa;
};
2.2 信号信息结构定义
用于发送信号
/* include/asm-generic/siginfo.h */
typedef struct siginfo {
int si_signo;
int si_errno;
int si_code;
union {
int _pad[SI_PAD_SIZE];
/* kill() */
struct {
pid_t _pid; /* sender's pid */
__ARCH_SI_UID_T _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
timer_t _tid; /* timer id */
int _overrun; /* overrun count */
char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
sigval_t _sigval; /* same as below */
int _sys_private; /* not to be passed to user */
} _timer;
/* POSIX.1b signals */
struct {
pid_t _pid; /* sender's pid */
__ARCH_SI_UID_T _uid; /* sender's uid */
sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct {
pid_t _pid; /* which child */
__ARCH_SI_UID_T _uid; /* sender's uid */
int _status; /* exit code */
clock_t _utime;
clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
int _trapno; /* TRAP # which caused the signal */
#endif
} _sigfault;
/* SIGPOLL */
struct {
__ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
} siginfo_t;
3. 定义信号处理函数
signal系统调用在内核中对应的是sys_signal,sigaction对应的是sys_sysaction:
/* kernel/signal.c */
/*
* For backwards compatibility. Functionality superseded by sigaction.
*/
// signal函数已经只是为了后向兼容了,以后尽量还是使用sigaction实现为好
asmlinkage unsigned long
sys_signal(int sig, __sighandler_t handler)
{
struct k_sigaction new_sa, old_sa;
int ret;
// 填写新的信号处理结构参数
// 最重要的是handler参数
new_sa.sa.sa_handler = handler;
new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
sigemptyset(&new_sa.sa.sa_mask);
// 进入do_sigaction函数处理
ret = do_sigaction(sig, &new_sa, &old_sa);
// 如果返回值为0(成功), 返回原来的信号处理函数
return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
}
/* arch/i386/kernel/signal.c */
// 注意输入的是老的信号处理结构
asmlinkage int
sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
int ret;
// act相当于新的信号处理结构定义
if (act) {
// 从用户层空间拷贝信号处理结构参数
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
__get_user(new_ka.sa