![](/img/trans.png)
[英]blocking function accept() restarts when SIGINT occurs even though SA_RESTART flag is set to zero
[英]Blocking SIGINT within an sa_handler in C
我正在嘗試編寫一個程序,它將設置警報 10 秒,在 10 秒后阻止 SIGINT,設置另一個警報 10 秒,然后解除阻止並忽略 SIGINT,設置另一個警報 10 秒然后終止。 我希望我可以在 sa_handler 中為 SIGALRM 執行所有操作,但它並沒有像我希望的那樣工作。 有可能做到這一點嗎? 編輯:當在 SIGALRM 的 sa 處理程序中時,我無法將 SIGINT 設置為阻塞。
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int ctrlct = 0;
int alrmct = 0;
void catchctrlc(int signo)
{
printf("Caught CTRL-C! <%d>\n", ++ctrlct);
}
void catchalrm(int signo)
{
sigset_t alrmset;
switch(alrmct)
{
case 0:
printf("Alarm 1\n");
if( (sigemptyset(&alrmset) == -1) || (sigaddset(&alrmset, SIGINT) == -1) )
printf("Failed to add SIGINT to the alrmset");
else if( sigprocmask(SIG_BLOCK, &alrmset, NULL) == -1 )
printf("Failed to block SIGINT");
break;
case 1:
printf("Alarm 2\n");
break;
case 2:
printf("Alarm 3\n");
exit(EXIT_SUCCESS);
break;
default:
break;
}
alrmct++;
alarm(10);
}
int main(void)
{
struct sigaction ctrlact, alrmact;
ctrlact.sa_handler = catchctrlc;
ctrlact.sa_flags = 0;
alrmact.sa_handler = catchalrm;
alrmact.sa_flags = 0;
/* Install signal handler for CTRL-C */
if((sigemptyset(&ctrlact.sa_mask) == -1) || (sigaction(SIGINT, &ctrlact, NULL) == -1))
perror("Failed to set sa_handler for SIGINT");
/* Install signal handler for SIGALRM */
if((sigemptyset(&alrmact.sa_mask) == -1) || (sigaction(SIGALRM, &alrmact, NULL)== -1))
perror("Failed to set sa_handler for SIGALRM");
alarm(10);
while(1){}
return 0;
}
當一個信號被傳遞時,kernel 將 ->blocked 信號保存到信號幀中,將傳遞的信號添加到 ->blocked 集中(除非指定 SA_NODEFER),並在從處理信號返回時恢復 ->blocked設置為信號幀中的一個,從而覆蓋所做的任何更改。
如果需要這種行為,我們可以通過在信號幀(位於用戶線程的堆棧上)上編輯保存的信號來克服它。 為此,我們需要為警報處理程序指定 SA_SIGINFO 標志,然后:
void catchalrm(int signo, siginfo_t * info, ucontext_t * context)
{
sigaddset(&context->uc_sigmask, SIGINT);
...
}
例如從信號返回時,恢復的->阻塞集將包含 SIGINT。
請注意,此行為可能是 linux 和體系結構特定的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.