1. 程式人生 > >自學Linux--sigaction function

自學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,其中可以指定2handler,一個是使用sigiinfo_t等引數的handler,即支援給handler更多的引數,使其可以知道自己是被什麼程序,那個使用者,發來的什麼訊號,發來該訊號的具體的原因是什麼,當然要像這樣,得給sigactionsa_flags設定SA_SIGINFO標記。

3.使用sigactionsa_flags標記還可以指定系統呼叫被這個訊號打斷後,是直接返回,還是自動

restart. 一個典型就是,一般我們不讓SIGALRM訊號將被打斷的系統呼叫restart,因為SIGALARM一般本來就是用來打斷一個block的呼叫的。

4. 為了模仿老的signal函式的作用,實現unreliable 的類似signal的操作,可以通過給sa_flags設定SA_RESETHAND使handler不會自動reinstall,以及SA_NODEFER標記來使在本訊號的handler內部,本訊號不被自動block,當然如果你手動在sa_mask中指定要block本訊號的話就可以將其block了。

5. 通過使用sigaction結構中的sa_mask,可以在該handler

執行的過程中,block一些訊號,注意,這個mask是與我們使用sigprocmask設定的mask不同的mask,這個mask的作用範圍僅限於本handler函式,而且他不會將我們用sigprocmask設定的mask取消,而僅僅是在其基礎上再次將一些訊號block掉,當handler結束時,系統會自動將mask恢復成以前的樣子,所以這個sigaction中的sa_mask只作用本訊號的handler的執行時間。

此外,系統為了避免一個signal handler的執行的時候再次被本signal打斷,就自動在本handler執行之前,將本signal加入sigactionsa_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可以連續傳送2SIGUSR1child,我們發現child並不響應,而是依然睡足她的剩下的時間。5秒鐘睡眠結束後,child醒了,它的handler退出,系統自動將臨時blockSIGUSR1 unblock,此時發現有pending SIGUSR1,因此將他deliverychild。於是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