1. 程式人生 > >APUE:信號

APUE:信號

queue 繼續 重新 情況 操作 setjmp cti -1 系統

信號是系統用來異步通知一個進程某些事件發生了的機制。從效果上來說,有點像中斷。信號發生時,打斷原有執行過程,進入信號處理函數(如果註冊了的話)或默認處理(忽略或終止程序),結束後恢復原有流程。默認情況下,信號處理過程中可能會被其它信號繼續中斷,所以需要考慮各種可能的情況,比如庫函數重入的問題。信號處理函數執行的上下文是在原有棧幀基礎上繼續的,所以可以用 setjmp() 和 longjmp()。

一些常見的信號

  • SIGABRT
  • SIGALRM
  • SIGCHLD
  • SIGINT
  • SIGQUIT
  • SIGSEGV
  • SIGUSR1
  • SIGUSR2

註冊信號處理函數

typedef void (*__sighandler_t) (int);
__sighandler_t signal (int __sig, __sighandler_t __handler); struct sigaction { union { /* Used if SA_SIGINFO is not set. */ __sighandler_t sa_handler; /* Used if SA_SIGINFO is set. */ void (*sa_sigaction) (int, siginfo_t *, void *); } __sigset_t sa_mask; int sa_flags; }; int sigaction (int __sig, const struct sigaction *__restrict __act, struct sigaction *__restrict __oact);

信號處理函數

#define SIG_ERR	((__sighandler_t) -1)		/* Error return.  */
#define SIG_DFL	((__sighandler_t) 0)		/* Default action.  */
#define SIG_IGN	((__sighandler_t) 1)		/* Ignore signal.  */

產生信號

int kill (__pid_t __pid, int __sig);
int raise (int __sig);
unsigned int alarm (unsigned int __seconds);
void abort (void);

int sigqueue (__pid_t __pid, int __sig, const union sigval __val);

信號集

int sigemptyset (sigset_t *__set);
int sigfillset (sigset_t *__set);
int sigaddset (sigset_t *__set, int __signo);
int sigdelset (sigset_t *__set, int __signo);
int sigismember (const sigset_t *__set, int __signo);

更多函數

// 進程阻塞直到有信號產生
int pause (void);

// 阻塞信號
int sigprocmask (int __how /* = SIG_BLOCK or SIG_UNBLOCK or SIG_SETMASK */, const sigset_t *__restrict __set, sigset_t *__restrict __oset);
// 獲得未決(已產生但未遞送)信號
int sigpending (sigset_t *__set);

// 修改信號屏蔽字然後阻塞直到有信號產生
// 與 sigprocmask() + pause() 相比,是原子操作
int sigsuspend (const sigset_t *__set);

sigsetjmp() 和 siglongjmp()

#define sigsetjmp(env, savemask)	__sigsetjmp (env, savemask)
void siglongjmp (sigjmp_buf __env, int __val);

與 setjmp() 和 longjmp() 相比,如果 savemask 不為 0,使用 siglongjmp() 跳出信號處理函數時會恢復信號屏蔽字。

中斷的系統調用

ioctl()、read()、readv()、write()、writev() 針對低速設備(可能會被永遠阻塞,如管道、終端、網絡等)時可能會被信號打斷,如果使用 sigaction() 設置信號處理函數並指定 SA_RESTART 時會重新啟動,否則返回 -1 並設置 errno 為 EINTR。

其它概念

  • 要註意不可靠的信號,比如在安裝信號處理函數後與調用等待函數之間,信號可能會發生。
  • 必須註意可重入函數,尤其是 malloc()、free() 等

APUE:信號