您的位置:首页 > 运维架构 > Linux

linux 信号设计 --不断补充--欢迎指正讨论

2015-12-06 14:23 579 查看
Linux 信号产生条件:
1. 用户输入
2. 系统异常:浮点异常和非法内存段访问
3. 系统状态变化:比如alarm 定时器到期将引起SIGALRM信号
4. 运行kill 命令

1. 发送信号:
int kill(pid_t pid, int sig);

参数:
pid = 0 信号发给本进程内的其他进程
注意sig = 0情况,=0 表示不发送任何信号,用来检测进程或是进程组是否存在

返回值:
成功:0 失败:-1并设置errno

2. 进程在收到信号时,假如不想用系统默认的方式处理信号需要提前定义扑捉信号,并设置信号收到后的处理函数
2.1 扑捉信号:
_sighandler_t signal(int sig, _sighandler_t _handler);

参数:

返回值:
成功: 失败:返回SIG_ERR并设置errno

3 加强版的扑捉信号:在收到sig后,执行act.handler函数时,屏蔽act.sa_mask中的信号(在执行sig信号处理函数时,可能收到act.sa_mask的信息,为了避免不必要的中断,暂时屏蔽)
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);

参数:
sa_flags成员用于设置程序收到信号时的行为。
SA_RESTART: 重新调用被该信号终止的系统调用
SA_RESETHAND:信号处理函数执行完以后,恢复信号的默认处理方式

4. 信号处理函数:进程在收到信号之后,不是执行信号的默认动作,执行该函数
信号处理函数原型:
_sighandler_t signal(int sig, _sighandler_t _handler);

参数:
sig:扑捉到的信号

返回值:
返回SIG_DEF(假如是第一次调用signal) 或是 前一次调用signal函数时传入的函数指针

示例:
1. 扑捉信号
bcl_sig_sethandler( SIGTERM, bcl_signal_handle );

1.1 对扑捉函数sigation封装
Sigfunc bcl_sig_sethandler( int signo, Sigfunc sighandler )
{
struct sigaction sa, sav;

sigemptyset( &sa.sa_mask );
sigaddset( &sa.sa_mask, signo );
sa.sa_handler = sighandler;
sa.sa_flags = 0; //收到信号时的行为

if ( signo == SIGALRM ) {
#ifdef SA_INTERRUPT
sa.sa_flags |= SA_INTERRUPT; //中断系统调用
#endif
}
else {
#ifdef SA_RESTART
sa.sa_flags |= SA_RESTART; //除了时钟信号需要中断系统调用,其他都恢复
#endif
}

if ( sigaction( signo, &sa, &sav ) < 0 ) {
bclerreg( E_OSCALL, __FILE__, __LINE__, "sigaction()" );
return SIG_ERR;
}
return sav.sa_handler; //signal函数返回上一次的传入signal函数的信号处理函数
}

1.2 信号处理函数
void bcl_signal_handle( int sig )
{
pid_t cpid;
int flag;

switch ( sig ) {
case SIGALRM:
if ( SIGALRMtrap != NULL ) {
signal( SIGALRM, bcl_signal_handle );//再次扑捉
(*SIGALRMtrap)();
}
break;
case SIGURG:
break;
#ifdef SIGEMT
case SIGEMT: /* EMT instruction */
#endif
case SIGFPE: /* floating point exception */
case SIGBUS: /* bus error */
case SIGSEGV: /* segmentation violation */
fprintf( stderr, "Process[%d] recv signal[%d], coredump!!!\n", \
getpid(), sig );
abort(); /*收到上面4个信号,都是退出,case后面都没有跟break*/

#ifdef SIGSYS
case SIGSYS: /* Bad argument to system call */
#endif
case SIGPIPE: /* Pipe broken */
break;
case SIGTERM: /* software termination signal from kill */
if ( SIGTERMtrap != NULL ) {
(*SIGTERMtrap)();
signal( SIGTERM, bcl_signal_handle );
}
else
exit( 0 );
case SIGUSR1: /* 用户自定义信号 */
if ( SIGUSR1trap != NULL )
(*SIGUSR1trap)();
signal( SIGUSR1, bcl_signal_handle );
break;
case SIGUSR2: /* user defined signal 2 */
sigusr2_flag = 1;
if ( SIGUSR2trap != NULL )
(*SIGUSR2trap)();
signal( SIGUSR2, bcl_signal_handle );
break;
case SIGCHLD: /*子进程退出,父进程会受到这个信号,需要父进程清理子进程资源*/
while ( (cpid = waitpid(-1, &flag, WNOHANG)) > 0 ) {
if ( SIGCLDtrap != NULL )
(*SIGCLDtrap)( cpid, flag );
}
signal( SIGCHLD, bcl_signal_handle );
break;
}
}

2. 对于阻塞的系统调用,加上errno的判断,效果等同在sigaction中设置恢复系统调用
for(;;)
{
if ( (ret=recvmsg( sockfd, &msg, 0 )) <= 0 )
{
if ( errno == EINTR )/*做判断,假如是因为系统调用,需要重新调用,假如系统 调用中有时间参数,需要重新计算阻塞时间*/
continue;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: