Signal之基本操作

2020-07-01 14:59:54 浏览数 (2)

注册

要想使用Signal,首先需要注册Signal的处理函数,就像中断的ISR。最基本的方法是POSIX定义的sigaction()

代码语言:javascript复制
typedef unsigned long long sigset_t;
union sigval
    {
    int   sival_int;
    void *sival_ptr;
    };
typedef struct _Siginfo
    {
    int   si_signo;
    int   si_code;
    union sigval si_value;
    } siginfo_t;
struct sigaction
    {
    union
        {
        void (*__sa_handler)(int);
        void (*__sa_sigaction)(int, siginfo_t *, void *);
        } sa_u;
    #define  sa_handler sa_u.__sa_handler
    #define  sa_sigaction sa_u.__sa_sigaction
    sigset_t sa_mask;
    int      sa_flags;
    };
/*
 * POSIX定义的Signal处理函数的安装机制
 * sig   - Signal number
 * pAct  - 新的处理函数支持1个参数或3个参数
 * pOact - 获得之前的处理函数
 */
int sigaction
    (
    int               sig,
    struct sigaction *pAct,
    struct sigaction *pOact
    );

或者使用简化一些的sigvec()

代码语言:javascript复制
typedef unsigned long long sigset_t;
struct sigvec
    {
    void   (*sv_handler)(int);
    sigset_t sv_mask;
    int      sv_flags;
    };
/*
 * 简化一些的安装机制
 * sig   - Signal number
 * pVec  - 新的处理函数支持1个参数
 * pOvec - 获得之前的处理函数
 */
int sigvec
    (
    int            sig,
    struct sigvec *pVec,
    struct sigvec *pOvec
    );

而最简单的是直接使用signal()

代码语言:javascript复制
/*
 * 最简单的安装机制
 * sig      - Signal number
 * pHandler - 处理函数支持1个参数
 * 返回值是之前的处理函数
 */
void (*signal(int sig, void(*pHandler)(int)))(int);

等待

注册了Signal之后,这个任务就可以去忙自己的工作了。当相应的Signal被触发后,就会执行注册的函数,所以这个流程是异步的。那如果想同步操作呢?该任务就需要将自己阻塞,等待Signal将其唤醒

最简单的方法是pause()

代码语言:javascript复制
/*
 * 当前任务进入阻塞状态
 * 等待Signal激活
 */
int pause(); /* POSIX */

但有时候不希望被某些Signal打扰,那就使用sigsuspend()将它们屏蔽掉

代码语言:javascript复制
typedef unsigned long long sigset_t;
/*
 * 功能与pause()类似
 * 但忽略pSet指定的Signal
 */
int sigsuspend /* POSIX */
    (
    sigset_t *pSet
    );

甚至有时候不需要使用处理函数

代码语言:javascript复制
/*
 * 当前任务进入阻塞状态
 * 等待pSet指定的Signal激活
 * 通常使用sigprocmask()屏蔽其它Signal
 *
 * 由pSig返回接收到的Signal number
 * 并忽略相应Signal的处理函数
 */
int sigwait /* POSIX */
    (
    sigset_t *pSet,
    int      *pSig
    );

#define SI_SYNC     0 /* (Not posix) gernerated by hardware */
#define SI_USER    -1 /* signal from kill() function */
#define SI_QUEUE   -2 /* signal from sigqueue() function */
#define SI_TIMER   -3 /* signal from expiration of a timer */
#define SI_ASYNCIO -4 /* signal from completion of async I/O */
#define SI_MESGQ   -5 /* signal from arrival of a message */
#define SI_CHILD   -6 /* signal from child, stopped or terminated */
#define SI_KILL    SI_USER
/*
 * 功能与sigwait()类似
 * 由pInfo->si_signo返回接收到的Signal number
 * 由pInfo->si_code返回Signal的触发源
 * 由pInfo->si_value返回Queued Signal的Value
 */
int sigwaitinfo
    (
    sigset_t  *pSet,
    siginfo_t *pInfo
    );

typedef unsigned long time_t;
struct timespec
    {
    time_t tv_sec;
    long   tv_nsec;
    };
/*
 * 功能与sigwait()类似
 * 由pTimeout设置超时机制
 */
int sigtimedwait
    (
    sigset_t        *pSet,
    siginfo_t       *pInfo,
    struct timespec *pTimeout
    );

触发

那如何产生Signal呢?简单的方法是raise()和kill()

代码语言:javascript复制
/*
 * 向自己发送一个Signal
 */
int raise
    (
    int sig
);
/*
 * 向tid发送一个Signal
 */
int kill
    (
    TASK_ID tid,
    int     sig
);

复杂一点的函数是sigqueue()

代码语言:javascript复制

/*
 * 向tid发送一个可以排队的Signal
 * 并附带一个value
 */
int sigqueue
    (
    TASK_ID      tid,
    int          sig,
    union sigval value
);

还有一个特殊的封装 - alarm(),详情见《Utility之定时(2)》

代码语言:javascript复制
/* 向自己发送SIGALRM */
unsigned int alarm /* POSIX */
    (
    unsigned int secs
    );

最后跑一个最简单的小栗子

我是泰山,专注VX好多年!

一起学习,共同进步!

0 人点赞