分类:
2008-12-08 12:12:09
10.8 reliable signal terminology and semantics
正常的signal发出的过程是:一个signal 从他被生成,然后被delivery给接受进程,它会被接受进程的process table项加标记。如果该signal 被block了,就暂时不会delivery,这就叫做pending signal。
Reliable signal就需要比unreliable signal提供更好的机制保证不造成signal lost:
1.自动reinstall
2. 可以block signal,并且在unblock之后还可以将以前被block的signal找出来去处理,如果更好的话,还可以支持同时queue多个pending signal.
Block signal的过程是这样的,首先设定你要block一个signal,然后当signal发生之后,kernel会给该process table加一些标记表明你接受到了一种signal。如果你对该signal的处理是default或者catch(当然你已经block了该signal),那么该signal就保持pending状态,直到你unblock了该signal,或者你将该signal的处理方式改为ignored。如果你是unblock了该signal,那么就会按照默认的或者你指定的方式去处理该signal,如果是改为ignored,那么当然该信号就被忽略了。
显然,block信号有个好处就是我们没有丢失以前丢失的信号,而且我们保证在某时间段内不受signal的打扰。
那么怎么样去block一个信号呢?怎么样查看block了多少个pending的信号呢?有函数:
Sigprocmask使用sigset_t类型可以设置对信号的block mask
Sigpending可以查看一个进程此时block了多少个pending的信号呢
关于signal的queue: 注意,block signal queue是posix.1的real-time extension才支持的,有的unix版本不支持queue,仅支持记录一个被block的signal。Linux里面的real time signal是采用了这个机制的 可以支持queue的signal,而linux的普通的standard signal是不支持queue的,即被block的signal,只能记载一次发生。这个我做了测试,而所谓的real time signal的signal编号一般都大于32,位于32到64之间,而且据说根据不同的libgc的实现不同,其具体的编号范围也不同,所以编码的时候据说最好要使用SIGRTMIN+n来使用,而不是直接用具体的信号值。Real time signal是没有名字的,因为他们一般用来由用户自定义其用途。具体的real time signal在linux下的资料见:
下面是一段摘抄,讲述了sigqueue这个用来发送可以被queued 的real time signal的函数语普通kill函数的区别:
The differences between kill() and sigqueue() are:
如下是我写的测试一般的signal是否支持被queue的代码:
#include
#include
#include
#include
#include
void nullhandler( int num )
{
puts( "child received signal" );
}
int main()
{
setbuf( stdout, NULL );
int pid = fork();
if( pid == 0 )
{
//child
puts("child started, we will block some signals");
sigset_t maskset,oldset,oldset1;
sigemptyset( &maskset );
sigaddset( &maskset, SIGUSR1 );
sigprocmask( SIG_BLOCK, &maskset, &oldset );
struct sigaction act, oldact;
act.sa_handler = nullhandler;
sigemptyset( &act.sa_mask );
if( sigaction( SIGUSR1, &act, &oldact ) < 0 )
{
puts(" child install handler failed");
return -1;
}
puts("child went to sleep ...");
sleep(5);
puts("child wake up...");
sigset_t pendset;
if( sigpending( &pendset ) < 0 )
{
puts("get pending signal failed");
return -1;
}
if( sigismember( &pendset, SIGUSR1 ) )
puts("SIGUSR1 is pending signal");
else
puts("SIGUSR1 is pending signal");
puts("child is unblocking signal");
if( sigprocmask(SIG_UNBLOCK, &maskset, &oldset1 ) < 0 )
puts("unblock signal failed");
else
puts("unblock signal success");
puts("child is quiting");
exit(0);
}
sleep(1);
puts( " father send SIGUSR1 once" );
int ret = kill( pid, SIGUSR1 );
puts( " father send SIGUSR1 twice" );
ret = kill( pid, SIGUSR1 );
waitpid( pid, 0, 0);
puts("father is quiting");
return 0;
}
如下使测试结果:
shaoting@desktopbj-LabSD:/home/shaoting/mytest> ./a.out
child started, we will block some signals
child went to sleep ...
father send SIGUSR1 once
father send SIGUSR1 twice
child wake up...
SIGUSR1 is pending signal
child is unblocking signal
child received signal
unblock signal success
child is quiting
father is quiting
可见父亲发送了2个SIGUSR信号,儿子将其block,但当unblock之后,只作出一个响应,即只记录了一个信号。