自學Linux--sigaction function
#include<signal.h>
int sigaction(int sig, struct sigaction *act , struct sigaction *oact) ;
struct sigaction{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
這個函式可以:
1. 給一個signal安裝一個handler,並且在使用sigaction修改該handler之前,不用reinstall
2. 使用sigaction結構,該結構包含handler,其中可以指定2個handler,一個是使用sigiinfo_t等引數的handler,即支援給handler更多的引數,使其可以知道自己是被什麼程序,那個使用者,發來的什麼訊號,發來該訊號的具體的原因是什麼,當然要像這樣,得給sigaction的sa_flags設定SA_SIGINFO標記。
3.使用sigaction的sa_flags標記還可以指定系統呼叫被這個訊號打斷後,是直接返回,還是自動
4. 為了模仿老的signal函式的作用,實現unreliable 的類似signal的操作,可以通過給sa_flags設定SA_RESETHAND使handler不會自動reinstall,以及SA_NODEFER標記來使在本訊號的handler內部,本訊號不被自動block,當然如果你手動在sa_mask中指定要block本訊號的話就可以將其block了。
5.
通過使用sigaction結構中的sa_mask,可以在該handler
此外,系統為了避免一個signal handler的執行的時候再次被本signal打斷,就自動在本handler執行之前,將本signal加入sigaction的sa_mask中,使本handler的執行過程中,不會受到本signal的巢狀打擾,單是如果本handler對應的訊號的確發生了,那麼該訊號會在本handler執行完後執行,但只執行一次,因為只能記錄一次,當然如果在這次新的執行中,又發生了這種情況,應該往復下去。下面就是一段程式碼,它驗證瞭如下幾點:
(1).Sigaction會使handler自動將本signal給臨時block
(2).在一個handler執行過程中被臨時block掉的訊號也會被記錄,等handler完成後會被delivery。
下例子中,child一開始就pause()等待訊號來臨,father給他傳送SIGUSR1訊號,然後father就進入1秒鐘的睡眠,這是為了等child在他的handler裡面進入睡眠。Child受到SIGUSR1後。立即執行handler,它會進入5秒鐘的睡眠。那麼可見,等father睡了1秒鐘後,child還在睡眠,並且在其handler裡面睡眠。此時father可以連續傳送2次SIGUSR1給child,我們發現child並不響應,而是依然睡足她的剩下的時間。5秒鐘睡眠結束後,child醒了,它的handler退出,系統自動將臨時block的SIGUSR1 unblock,此時發現有pending 的SIGUSR1,因此將他delivery給child。於是child再次進入handler,此時father已經不再發送訊號了,就等著孩子結束呢。所以handler結束後,child就繼續執行,退出,然後father也就退出了。#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
void nullhandler( int num )
{
puts( "child received signal" );
puts( "child sleep 5 secs in handler..." );
sleep(5);
puts( "child wake up in handler after 5 secs" );
}
int main()
{
setbuf( stdout, NULL );
int pid = fork();
if( pid == 0 )
{
//child
puts("child started");
printf("%d",getpid());
/*
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,0 ) < 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 waiting for signal...");
/*pause函式只是簡單地將程序掛起,直至程序接受到一個terminal訊號,或是一個訊號函式將訊號捕捉,並進行呼叫。*/
pause();
puts("child returnd from signal handler");
puts("child is quiting");
exit(0);
}
sleep(1);
puts( " father send SIGUSR1 once" );
int ret = kill( pid, SIGUSR1 );
puts("father sleep 1 sec to ensure child is now in signal handler");
sleep(1);
puts( " father send SIGUSR1 twice" );
ret = kill( pid, SIGUSR1 );
puts( " father send SIGUSR1 third times" );
ret = kill( pid, SIGUSR1 );
/*等待子程序的結束。*/
waitpid( pid, 0, 0);
puts("father is quiting");
return 0;
}
輸出結果:
child started
child waiting for signal...
father sendSIGUSR1 once
father sleep 1 sec to ensure child is now in signal handler
child receivedsignal
child sleep 5 secs in handler...
father sendSIGUSR1 twice
father sendSIGUSR1 third times
child wake up in handler after 5 secs
child receivedsignal
child sleep 5 secs in handler...
child wake up in handler after 5 secs
child returnd from signal handler
childis quiting
father is quiting感謝大牛文章的指導:http://blog.chinaunix.net/space.php?uid=12072359&do=blog&id=2961076