1. 程式人生 > >sigaction函式 和 sigqueue函式(訊號的傳送和安裝)

sigaction函式 和 sigqueue函式(訊號的傳送和安裝)

    [1]sigqueue(傳送訊號)
        

int sigqueue(pid_t pid, int sig, const union sigval value);
引數: pid:     要傳送訊號的程序ID
                 sig:      要傳送的訊號
              value: 傳送的伴隨資料,該引數的資料型別是聯合體
                union sigval {
                    int sival_int;
                    void *sival_ptr;    // 幾乎不用(每個程序都有獨立的地址空間)
                };

       
            //考慮到不同的程序有各自獨立的地址空間,傳遞指標到另一個程序幾乎沒有任何意義。因此 sigqueue 函式很少傳遞指 針( sival_ptr ),大多是傳遞整型( sival_int )。 

        1.傳統的訊號多用 signal/kill 這兩個函式搭配
        2.signal函式的表達力有限,控制不夠精準;所以引入了sigqueue函式來完成實時訊號的傳送
        3.sigqueue函式也可以傳送空訊號(訊號0)來檢查程序是否存在。
        4.和 kill 函式不同的地方在於,它不能通過將pid指定為負值而向整個程序組傳送訊號。

    [2]    sigaction(安裝訊號)
      

 int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

        1.引數: signum: 訊號編號
          

 1.struct sigaction {    // 第二個引數
                union {
                    void (*sa_handler)(int);//sa_flags裡沒有設定SA_SIGINFO標記的訊號處理函式
                        //sa_flags裡設定了SA_SIGINFO標誌, 的訊號處理函式
                    void handle(int, siginfo_t *info, void *ucontext);
                        // 收到的額外資料儲存在siginfo_t->si_value中的si_int和si_ptr中
                }
                sigset_t sa_mask;            // 阻塞訊號集
                int sa_flags;                // 標誌
                void (*sa_restorer)(void);    // 恢復處理程式
            };      

            2.

siginfo_t {     // handle訊號處理函式的第二個引數    
                int si_signo; // 訊號的值
                int si_code;  // 訊號來源:SI_USER.SI_TKILL.SI_QUEUE.. 
                pid_t si_pid;    // 訊號傳送程序的程序 ID 。
                uid_t si_uid;   //訊號傳送程序的真實使用者 ID 。
                union sigval si_value; //sigqueue 函式傳送訊號時所帶的伴隨資料。
                ...
            }

            3.ucontext是 void* 型別的,其實它是一個 ucontext_t 型別的變數。
                這個結構體提供了程序上下文的資訊,用於描述程序執行訊號處理函式之前程序所處的狀態。通常情況下訊號處理函式很少會用到這個變數

            4. sa_flags的含義
                1.SA_NOCLDSTOP
                    一旦父程序為SIGCHLD訊號設定了這個標誌位,那麼子程序停止和子程序恢復這兩件事情,就不會向父程序傳送 SIGCHLD訊號了但是子程序切換為SIGCONT時還是會給父程序傳送SIGCHLD訊號。

                2.SA_NOCLDWAIT
                    如果父程序為SIGCHLD設定了SA_NOCLDWAIT 標誌位,那麼子程序退出時,就不會進入殭屍狀態,而是直接自行 了斷。 對於Linux而言,子程序轉換切換為SIGSTOP.SIGCONT.SIGKILL時都會給父程序傳送SIGCHLD訊號。這點 和上面的 SA_NOCLDSTOP 略有不同。

                3.SA_ONESHOT 和 SA_RESETHAND
                    這兩個標誌位的本質是一樣的,表示訊號處理函式是一次性的,訊號遞送出去之後,訊號處理函式便恢復成預設值                       SIG_DFL 。

                4.SA_NODEFER 和 SA_NOMASK
                    這兩個標誌位的作用是一樣的,在訊號處理函式執行期間,不阻塞當前訊號。

                5.SA_RESTART
                    這個標誌位表示,如果系統呼叫被訊號中斷,則不返回錯誤,而是自動重啟系統呼叫

                6.SA_SIGINFO
                    沒有設定SA_SIGINFO:
                        跟signal使用方法相同, 使用一個引數的訊號處理函式
                        void (*sa_handler)(int);
                    設定了SA_SIGINFO:
                        1.這個標誌位表示訊號傳送者會提供伴隨資料。這時使用帶3個引數的訊號處理函式
                            void handle(int, siginfo_t *info, void *ucontext);    
                        2.能獲取到傳送程序的PID、UID.訊號來源.及傳送的額外資訊...


        2.注意
            1.對SIGKILL 和 SIGSTOP,不可以為它們安裝訊號處理函式,也不能遮蔽掉這些訊號。
                若通過 sigaction 強行給 SIGKILL 或 SIGSTOP 註冊訊號處理函式,則會返回-1,並置errno為EINVAL。    


   [3].使用例子

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <signal.h>

#define ERR printf("ERR: %d\n", __LINE__)
#define CUR printf("CUR: %d\n", __LINE__)
#define SIG_PHYSICAL 	SIGRTMIN+1		// 運動訊號
enum physical {
	BASKETBALL = 0x1,	//	籃球
	TENNIS 	   = 0x2,	// 網球
	PINGPONG   = 0x3,	// 乒乓球
};

// 無SA_SIGINFO標誌時,安裝的訊號處理函式
static void handle_(int signum)
{	
	printf("sig: sa_handler, no SA_SIGINFO\n");
}

// 有SA_SIGINFO標誌時,安裝的訊號處理函式
static void _handle(int signum, siginfo_t *info, void *ucontext)
{		CUR;

	switch(info->si_value.sival_int)	{
		case BASKETBALL:
			printf("I will go basketball\n"); break;
		case TENNIS:
			printf("I will go tennis\n");	  break;	
		case PINGPONG:
			printf("I will go pingpong\n");	  break;	
		default:
			return;							  break;
	}
	printf("send pid = %d\n", info->si_pid);
	printf("send si_uid = %d\n", info->si_uid);
	printf("------------------------------\n");
}

void sig_eat(int signum)
{	
	printf("I will go eat\n");
}
int main(int argc, char **argv)
{
	int ret, cldpid;
	struct sigaction act;
	sigset_t block_mask;	// 阻塞訊號集
  	union sigval sigval1, sigval2,sigval3;
	
	sigval1.sival_int = BASKETBALL;
	sigval2.sival_int = TENNIS;
	sigval3.sival_int = PINGPONG;

	printf("Usage:\n");
	printf("%s [SA_SIGINFO]\n", argv[0]);
	
	// 註冊訊號處理函式
	if ((argc > 1) && (!strcmp(argv[1], "SA_SIGINFO"))){
		
		memset(&act, 0, sizeof(act));
		act.sa_sigaction = (void (*)(int, siginfo_t *, void *))_handle;	// 有SA_SIGINFO標誌時,安裝的訊號處理函式
		act.sa_flags = SA_SIGINFO | SA_RESTART;	
		sigaction(SIG_PHYSICAL, &act, NULL);	//安裝一個可靠訊號
	}
	else {
		memset(&act, 0, sizeof(act));
		act.sa_handler = handle_;	// 無SA_SIGINFO標誌時,安裝的訊號處理函式
		act.sa_flags =  0;	
		sigaction(SIG_PHYSICAL, &act, NULL);	//安裝一個可靠訊號
	}
	ret = fork();
	if (ret < 0) {
		ERR;
		return -1;
	}
	else if(!ret)	{
		while(1){
			sleep(2);
			cldpid = getpid();
			sigqueue(cldpid, SIG_PHYSICAL, sigval1);		
			sleep(1);	
			sigqueue(cldpid, SIG_PHYSICAL, sigval2);
			sleep(1);	
			sigqueue(cldpid, SIG_PHYSICAL, sigval3);		
			sleep(3);
		}
	}
	while(1)
			pause();
	return 0;
}

 

執行結果:

[email protected]_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$ ./a.out
Usage:
./a.out [SA_SIGINFO]
sig: sa_handler, no SA_SIGINFO
sig: sa_handler, no SA_SIGINFO
sig: sa_handler, no SA_SIGINFO
^C

[email protected]_hua_shu$ ./a.out SA_SIGINFO
Usage:
./a.out [SA_SIGINFO]
CUR: 36
I will go basketball
send pid = 11627
send si_uid = 1000
------------------------------
CUR: 36
I will go tennis
send pid = 11627
send si_uid = 1000
------------------------------
CUR: 36
I will go pingpong
send pid = 11627
send si_uid = 1000
------------------------------
^C
[email protected]_hua_shu$