Chinaunix首页 | 论坛 | 博客
  • 博客访问: 184963
  • 博文数量: 38
  • 博客积分: 1576
  • 博客等级: 上尉
  • 技术积分: 516
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-24 23:06
文章分类
文章存档

2017年(1)

2013年(1)

2011年(23)

2010年(4)

2009年(9)

我的朋友

分类:

2011-07-04 20:32:04

1 概念
1.1 产生条件
- 用户按下了某些终端键(如Ctrl-c)时
- 硬件异常产生信号
- 进程用kill(2)函数给另一个进程或进程组发送信号
- 用户用kill(1)命令发送信号给进程
- 某种软件条件发生(如SIGPIPE等信号)
1.2 动作
- 忽略此信号
- 捕获信号
- 执行系统默认动作
1.3 信号分类
-
不可靠信号,即普通信号。假如一个进程接收到一个普通信号,而进程的未决信号集(pending
signals)中存在相同的信号,则这个新发送的信号丢失。即同一时间进程的未决信号集中只可能有一个普通信号。文档
/usr/include/bits/signum.h中定义了任何普通信号。
- 可靠信号,即实时信号。信号值在SIGRTMIN(32)和SIGRTMAX(64)之间的信号。实时信号每次都会被加入到未决信号集中。
2 signal函数
2.1 函数原形
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
2.2 说明
handler的值能够是SIG_IGN(忽略信号),SIG_DFL(默认行为)或是用户自定义的一个信号处理函数。返回的是之前的信号处理函数指针或SIG_ERR。
3 中断的系统调用
假如进程执行一个低速系统调用而阻塞期间捕获到一个信号,该系统调用会被中断返回出错,errno设为EINTR。4.2BSD引入了自动再启动的系统调用包括:read、readv、write、writev、ioctl、wait和waitpid。
4 可再入函数
不可再入函数一般是指:a)使用了静态数据结构,b)调用了malloc或free或c)标准I/O函数。假如在信号处理函数种调用不可再入函数,则可能会引起错误。
即使是可载入函数,因为errno每个进程只有一个,也有可能引起错误。因此一般调用使用errno的系统调用之前都要保存errno,在调用后再恢复。
5 发送等待信号
5.1 相关函数
int kill(pid_t pid, int sig);
int raise(int sig);
unsigned int alarm(unsigned int seconds);
int pause(void);
5.2 说明
kill能够给人以进程发送信号,raise则给当前进程发送信号。
alarm则配置一个闹钟值,所配置的时间超过后,产生一个SIGALARM信号,其默认动作时终止该进程。
pause是当前进程挂起直到接收到一个信号。
实例:
- sleep的不完整的实现:signals/sleep1.c
6 信号集
6.1 相关函数
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
6.2 说明
sigset是表示多个信号的数据类型。sigemptyset函数使信号集set不包含任何信号,sigfillset使set包含任何的信号。sigaddset和sigdelset添加和删除一个信号。sigismember检测信号集是否包含特定的信号。
7 POSIX信号处理函数
7.1 相关函数
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);
7.2 说明
用sigprocmask设定进程信号屏蔽字,参数how有三个可选项:SIG_BLOCK,SIG_UNBLOCK和SIG_SETMASK。
sigpending返回对于调用进程被阻塞的和当前未决的信号集。
sigaction取代了早期的signal函数,用于设定和信号相关联的处理动作。参数act的类型为:
struct sigaction {
       void (*sa_handler)(int);
       void (*sa_sigaction)(int, siginfo_t *, void *);
       sigset_t sa_mask;
       int sa_flags;
}
因为可能会用union实现,只能给两个信号处理函数指针sa_handler和
sa_sigaction中的一个赋值。sa_mask是信号处理函数执行时应该被屏蔽的信号。flag则是一些标识,要使用sa_sigaction则
必须设定SA_SIGINFO,这样信号的一些信息及传递的变量才会被配置到sa_sigaction的第二个参数中。关于sa_sigaction第二
个参数的使用,参看man文档。
sigsuspend以参数mask为屏蔽字是进程挂起直到接收到一个信号。相当于以原子操作实现:
sigprocmask(SIG_SETMASK, &mask, &oldmask);
pause();
sigprocmask(SIG_SETMASK, &oldmask, NULL);
实例:
- 父子进程同步的实现:lib.rhlin /tellwait.c
- 用sigsuspend保护临界区:signals/suspend1.c
- 用sigsuspend等待一个全局变量被配置:signals/suspend2.c
- abort的实现:signals/abort.c
- system的POSIX.2实现:signals/system.c
- 处理SIGTSTP信号(Ctrl-z):signals/sigtstp.c
8 非局部跳转
8.1 相关函数
int sigsetjmp(sigjmp_buf env, int savesigs);
void siglongjmp(sigjmp_buf env, int val);
8.2 说明
这两个函数和setjmp、longjmp之间的唯一区分是sigsetjmp增加了一个参数。savesigs为非0,则sigsetjmp在env中保存进程的当前屏蔽字。
阅读(1310) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~