分类: LINUX
2017-03-12 17:08:50
原文地址:linux 信号的实现及其使用 作者:zghover
linux 内核信号机制的实现及其使用
1, 信号
*信号的作用
.让进程知道已经发生了一个特定的事件
.强迫进程执行它自己代码中的信号处理程序
*实时信号和常规信号
POSIX引入了一类新的信号,叫实时信号,在linux中它们的编码范围是32-64。 它们与常规信号的不同之处在于:
.实时信号必须排队以便发送的多个信号都能被接受到
.常规信号不需要排队,若一个常规信号被发送多次,那么只有其中一个发送到接受进程。
*信号的特点
.信号可以随时发送给一个状态不可预知的进程。
.发送给非运行状态的进程的信号必须由内核保存,知道进程恢复运行。
.阻塞一个信号要求一个信号的传递延迟,直到最后接触阻塞,这使得该信号产生一段时间后才能对其进行传递。
*信号的产生和传递
.信号的产生:内核更新目标进程的数据结构,以表示一个新的信号已经被发送。
.信号的传递:内核强迫进程通过以下方式对信号做出动作:或改变目标进程的执行状态,或开始执行一个特定的信号处理函数,或两者同时进行。
.挂起信号:已经产生但是还没有被传递的信号。
.在执行一个信号的处理函数时,内核会自动阻塞该信号,直到处理函数结束。
*信号的阻塞和忽略
.信号的阻塞:该信号不被传递,只有在信号被解除阻塞后才传递它。
.忽略信号:一个被忽略的信号总是被传递,但没有进一步的操作。
.SIGKILL,SIGSTOP信号不可以被显示的忽略,捕获或阻塞。
*信号和线程
.信号处理函数必须在多线程应用的所有线程之间共享;但每个线程可以有自己的信号挂起掩码和阻塞信号掩码。
.kill()和sigqueue()必须向所有的多线程应用,而不是某个特殊的线程发送信号。
.若向多线程应用程序发送了一个致命信号,那么内核将杀死该应用的所有线程,而不只是其中一个线程。
2, 数据结构
// 进程秒数符中信号相关的数据结构
struct task_struct {
...
/* signal handlers */
struct signal_struct *signal; //进程信号描述指针
struct sighand_struct *sighand; //进程信号处理程序描述符指针
sigset_t blocked, real_blocked; //被阻塞的信号掩码,和被阻塞的临时掩码
struct sigpending pending; //存放私有挂起信号的结构
unsigned long sas_ss_sp; //信号处理函数备用堆栈地址
size_t sas_ss_size; //信号处理函备用堆栈大小
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
void *security;
struct audit_context *audit_context;
...
}
// 1-32 表示常规信号,32-64表示实时信号
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
//信号描述符结构
struct signal_struct {
atomic_t count; //使用计数
atomic_t live; //线程组中活动线程的数量
wait_queue_head_t wait_chldexit; /* for wait4() */ 系统中调用wait4中睡眠的进程的等待队列
/* current thread group signal load-balancing target: */
task_t *curr_target;
/* shared signal handling: */
struct sigpending shared_pending; //存放共享挂起信号的结构
/* thread group exit support */
int group_exit_code; //线程组的进程终止代码
/* overloaded:
* - notify group_exit_task when ->count is equal to notify_count
* - everyone except group_exit_task is stopped during signal delivery
* of fatal signals, group_exit_task processes the signal.
*/
struct task_struct *group_exit_task;
int notify_count;
/* thread group stop support, overloads group_exit_code too */
int group_stop_count;
unsigned int flags; /* see SIGNAL_* flags below */
/* POSIX.1b Interval Timers */
struct list_head posix_timers;
/* job control IDs */
pid_t pgrp;
pid_t tty_old_pgrp;
pid_t session;
/* boolean value for session group leader */
int leader;
struct tty_struct *tty; /* NULL if no tty */
/*
* Cumulative resource counters for dead threads in the group,
* and for reaped dead child processes forked by this group.
* Live threads maintain their own counters and add to these
* in __exit_signal, except for the group leader.
*/
cputime_t utime, stime, cutime, cstime;
unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
/*
* We don't bother to synchronize most readers of this at all,
* because there is no reader checking a limit that actually needs
* to get both rlim_cur and rlim_max atomically, and either one
* alone is a single word that can safely be read normally.
* getrlimit/setrlimit use task_lock(current->group_leader) to
* protect this instead of the siglock, because they really
* have no need to disable irqs.
*/
struct rlimit rlim[RLIM_NLIMITS];
};
//信号处理结构
struct sighand_struct {
atomic_t count;
struct k_sigaction action[_NSIG];
spinlock_t siglock;
};
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;
};
/*
* Real Time signals may be queued.
*/
//被阻塞信号队列结点
struct sigqueue {
struct list_head list;
spinlock_t *lock;
int flags;
siginfo_t info;
struct user_struct *user;
};
/* flags values. */
#define SIGQUEUE_PREALLOC 1
//信号阻塞队列
struct sigpending {
struct list_head list; //阻塞信号链表头,是sigqueue结构的队列
sigset_t signal; //阻塞信号位图
};
/* Type of a signal handler. */
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 ((__sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
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, 实现分析
参考资料:
《ulk》
《lsph》