1、註冊信號函數。
#include<signal.h>
void(*signal(int signumber,void ((*func)(int))(int)
signumber表示信號處理函數對應的信號。func是一個函數指針。此函數有一整型參數,並返回void型。其實func還可以取其他定值如:SIG_IGN,SIG_DFL.
SIG_IGN表示:忽略signumber所指出的信號。SIG_DFL表示表示調用系統默認的處理函數。signal函數的返回值類型同參數func,是一個指向某個返回值爲空並帶有一個整型參數的函數指針。其正確返回值應爲上次該信號的處理函數。錯誤返回SIG_ERR
signal示例如下:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
void func(int sig)
{
printf("I get asignal!\n");
}
int main()
{ charbuffer[100];
if(signal(SIGINT, func) == SIG_ERR)
{
printf("signalerror exit now\n");
exit(0);
}
printf("pid:%ld\n",(long)getpid());
for(;;)
{
fgets(buffer,sizeof(buffer),stdin);
printf("bufferis:%s\n",buffer);
}
return 0;
}
通常情況下一個用戶進程需要處理多個信號。可以在一個程序中註冊多個信號處理函數。一個信號可以對應一個處理函數,同時多個信號可以對應一個處理函數。
對於SIGINT信號 我們可以用ctrl+c或ctrl+z來中斷進程,來執行SIGINT註冊的函數。
2、 高級信號處理。
在linux系統提供了一個功能更強的系統調用。
#include <signal.h>
int sigaction(int signumbet,const structsigaction *act,struct sigaction *oldact)
此函數除能註冊信號函數外還提供了更加詳細的信息,確切瞭解進程接收到信號,發生的具體細節。
struct sigaction的定義如下:在linux2.6.39/include/asm-generic/signal.h中實現
struct sigaction
{
void(*sa_handler)(int);
void(*sa_sigaction)(int,siginfo_t *,void *);
sigset_t sa_mask;
int sa_flags;
}
siginfo_t在linux2.6.39/include/asm-generic/siginfo.h中實現:
sa_flags的取值如下表,取0表示選用所有默認選項。
SA_NOCLDSTOP:用於表示信號SIGCHLD,當子進程被中斷時,不產生此信號,當且僅當子進程結束時產生此信號。
SA_NOCLDWATI:當信號爲SIGCHLD,時可避免子進程僵死。
SA_NODEFER:當信號處理函數正在進行時,不堵塞對於信號處理函數自身信號功能。
SA_NOMASK:同SA_NODEFER
SA_RESETHAND:同SA_ONESHOT
SA_RESTART:是本來不能重新於運行的系統調用自動重新運行。
其實sinaction完全可以替換signal函數
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
void func(int sig)
{
printf("I get a signal!\n");
}
int main()
{ char buffer[100];
struct sigaction act;
act.sa_handler=func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGINT,&act, NULL) == -1)
{
printf("sigaction error exit now\n");
exit(0);
}
printf("pid:%ld\n",(long)getpid());
for(;;)
{
fgets(buffer,sizeof(buffer),stdin);
printf("buffer is:%s\n",buffer);
}
return 0;
}
//程序異常時, 打印函數調用棧代碼思路
/*=============================================================== * Copyright (C) 2014 All rights reserved. * * 文件名稱:bt.c * 創 建 者:sky * 創建日期:2014 .05. 17 * 描 述: * * 更新日誌: * ================================================================*/ #include<unistd.h> #include<stdio.h> #include <signal.h> #include <memory.h> #define TestPrintf(fmt, args...) \ printf("FUNC:: %s, line:%d\n", __FUNCTION__, __LINE__);\ printf(fmt,##args);\ printf("\n") char g_procname[100]={0}; char g_xthreadName[100]={0}; void getProcName(char * name, int length) { char filename[30]={0} ; int pid=getpid(); memset(name, 0, length); //read porcname TestPrintf(filename, "/proc/%d/cmdline", pid); FILE *fp = fopen(filename, "r"); if(fp == NULL) { TestPrintf("error return ..."); return ; } fread(name, length, 1,fp); TestPrintf("name :: %s\n", name); } void getThreadName(char * name, int length) { int ppid=getppid(); //read porcname char filename[20]={0}; TestPrintf(filename, "/proc/%d/stat", ppid); FILE *fp = fopen(filename, "r"); if(fp == NULL) { TestPrintf("error return ..."); return ; } fread(name, length, 1,fp); TestPrintf("threadname :: %s\n", name); } void parasregister(unsigned int * pc, unsigned int* bp, unsigned int* sp, void *ct) { return ; } void exception(int signum, siginfo_t *info, void *c) { TestPrintf("good"); unsigned int pc, bp, sp; if(signal(signum, SIG_DFL) == SIG_ERR) { TestPrintf("error\n"); return ; } else { TestPrintf("pc..\n"); } getProcName(g_procname, sizeof(g_procname)); getThreadName(g_xthreadName, sizeof(g_xthreadName)); //寄存器中保存程序當前pc sp bp parasregister(&pc, &bp, &sp, c); //可以解析elf文件符號表, 根據pc 指針定位當前函數 //根據具體平臺函數調用規則, 打印函數調用順序 TestPrintf("shit\n"); return ; } void backtraceinit() { struct sigaction act; act.sa_flags = SA_ONESHOT | SA_SIGINFO; act.sa_handler= exception; sigemptyset(&act.sa_mask); sigaction(SIGINT, &act, NULL); sigaction(SIGSEGV, &act, NULL); sigaction(SIGBUS, &act, NULL); } int main() { TestPrintf("cdcd\n"); backtraceinit(); while(1) sleep(200); }