linux 信号 底层实现,linux 信号的实现及其使用

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》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值