一、我们先来看下信号的所设计的数据结构:
struct task_struct {
int sigpending;
int exit_code, exit_signal;
/* Protects signal and blocked */
struct signal_struct *sig;
sigset_t blocked;
struct sigpending pending;
}
sigpending,是个整数,用来表示这个进程是否有信号在等待处理。
blocked表示信号遮蔽位,如果此位置1,说明不相应这个信号。
pending结构如下:
struct sigpending {
struct sigqueue *head, **tail;
sigset_t signal;
};
blocked和sigpending里面的signal都是64位的字段,sigset_t如下:
#define _NSIG 64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
typedef unsigned long old_sigset_t; /* at least 32 bits */
typedef struct {
unsigned long sig[_NSIG_WORDS];//两个32位就是64位
} sigset_t;
sigpending里面的signal和blocked,分别用来模拟中断控制器硬件中的中断状态寄存器(有啥中断待处理)和中断屏蔽寄存器(哪些中断不能处理)。
每当有一个中断请求到来时,中断状态寄存器中与之相应的某一位就被置为1,表示有相应的中断请求在等待处理,如果连续有两次中断请求到来,则有可能因为处理器来不及响应而被"合并"。
可是信号机制中就不同了,信号机制为信号准备一个队列,每产生一个信号就把它挂入这个队列,这样就可以确保一个信号也不会丢失了。所以在sigpending结构里面会有sigqueue结构。
sigpengding结构里面的sigqueue结构如下:
struct sigqueue {
struct sigqueue *next;
siginfo_t info;
};
siginfo_t如下面所讲。
发送信号,不但要将sigpengding结构里面的sig结构对应位置1,还要将分配一个sigqueue结构(里面siginfo_t结构si_signo代表哪个信号)链入到sigpengding结构里面的sigqueue。这样就不会丢失信号。只有sigpengding结构里面的sigqueue队列中对应信号所有的sigqueue结构全部移除后,sigpengding结构里面的sig结构对应位才置0。
下面我们解释signal_struct数据结构:
struct signal_struct {
atomic_t count;
struct k_sigaction action[_NSIG];//64,信号处理函数一共64个,这就是为什么blocked和sigpending里面的signal是64位
spinlock_t siglock;
};
struct k_sigaction {
struct sigaction sa;
};
struct sigaction {
union {
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo *, void *);
} _u;
sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
sigaction数据结构是信号处理函数。其中siginfo结构如下:
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 */
uid_t _uid; /* sender's uid */
} _kill;
/* POSIX.1b timers */
struct {
unsigned int _timer1;
unsigned int _timer2;
} _timer;
/* POSIX.1b signals */
struct {
pid_t _pid; /* sender's pid */
uid_t _uid; /* sender's uid */
sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct {
pid_t _pid; /* which child */
uid_t _uid; /* sender's uid */
int _status; /* exit code */
clock_t _utime;
clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
void *_addr; /* faulting insn/memory ref. */
} _sigfault;
/* SIGPOLL */
struct {
int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
} _sifields;
}siginfo_t
int sigaction (int signum, const struct sigaction *newact, struct sigaction *oldact);
asmlinkage unsigned long
sys_signal(int sig, __sighandler_t handler)
{
struct k_sigaction new_sa, old_sa;
int ret;
new_sa.sa.sa_handler = handler;
new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
ret = do_sigaction(sig, &new_sa, &old_sa);
return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
}
int
do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact)
{
struct k_sigaction *k;
if (sig < 1 || sig > _NSIG ||
(act && (sig == SIGKILL || sig == SIGSTOP)))//系统对信号SIGKILL和SIGSTOP的响应是不允许改变的
return -EINVAL;
k = ¤t->sig->action[sig-1];
spin_lock(¤t->sig->siglock);
if (oact)
*oact = *k;//返回原来的k_sigaction结构
if (act) {
*k = *act;//现在的k_sigaction结构赋值给current->sig->action[sig-1]
sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP));//SIGKILL和SIGSTOP相应屏蔽位也在每次设置"信号向量"时自动清0
/*
* POSIX 3.3.1.3:
* "Setting a signal action to SIG_IGN for a signal that is
* pending shall cause the pending signal to be discarded,
* whether or not it is blocked."
*
* "Setting a signal action to SIG_DFL for a signal that is
* pending and whose default action is to ignore the signal
* (for example, SIGCHLD), shall cause the pending signal to
* be discarded, whether or not it is blocked"
*
* Note the silly behaviour of SIGCHLD: SIG_IGN means that the
* signal isn't actually ignored, but does automatic child
* reaping, while SIG_DFL is explicitly said by POSIX to force
* the signal to be ignored.
*/
if (k->sa.sa_handler == SIG_IGN
|| (k->sa.sa_handler == SIG_DFL
&& (sig == SIGCONT ||
sig == SIGCHLD ||
sig == SIGWINCH))) {//新设置的向量为SIG_IGN时,或者为SIG_DFL而涉及的信号为SIGCONT、SIGCHLD和SIGWINCH之一时,如果已经有一个或几个这样的信号在等待处理,那么将这些已到达的信号丢弃
spin_lock_irq(¤t->sigmask_lock);
if (rm_sig_from_queue(sig, current))//丢弃已经到达的信号
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
}
}
spin_unlock(¤t->sig->siglock);
return 0;
}
rm_from_queue丢弃已到达的信号:
static int rm_from_queue(int sig, struct sigpending *s)
{
struct sigqueue *q, *