SylixOS信号系统(2)

信号机制原理

关键数据结构

POSIX标准定义了sigset_t类型来定义一个信号集,然而sigset_t类型在不同的系统可能有不同的定义方式,因此去猜测sigset_t类型是不明确的,在SylixOS中,将sigset_t定义成了unsigned long long型,也即是一个64位的数据类型,每一位代表了一个信号,最高位不被使用。
SylixOS信号机制的实现离开不了下面几个关键数据结构;

1. 信号上下文结构
typedef struct __sig_context {
    sigset_t              SIGCTX_sigsetSigBlockMask;       /*  当前信号屏蔽位              */
    sigset_t              SIGCTX_sigsetPending;            /*  当前由于被屏蔽无法运行的信号 */
    sigset_t              SIGCTX_sigsetKill;               /*  由 kill 发送但被屏蔽的信号  */

    struct sigaction      SIGCTX_sigaction[NSIG];          /*  所有的信号控制块            */
    LW_LIST_RING_HEADER   SIGCTX_pringSigQ[NSIG];          /*  由于被屏蔽无法运行的信号排队*/
    stack_t               SIGCTX_stack;                    /*  用户指定的信号堆栈情况      */

    LW_CLASS_SIGWAIT     *SIGCTX_sigwait;                  /*  等待信息                    */

#if LW_CFG_SIGNALFD_EN > 0
    BOOL                  SIGCTX_bRead;                    /*  是否在读 signalfd           */
    sigset_t              SIGCTX_sigsetWait;               /*  正在等待的 sigset           */
    LW_SEL_WAKEUPLIST     SIGCTX_selwulist;                /*  signalfd select list        */
#endif
} LW_CLASS_SIGCONTEXT;

下面分析这个结构中个成员含义:

  • SIGCTX_sigsetSigBlockMask是线程的信号屏蔽字,1的位对应信号将被屏蔽而不递送;
  • SIGCTX_sigsetPending包含了因屏蔽而不被递送的信号;
  • SIGCTX_sigsetKill中1的位对应了应kill函数发送的信号,此类信号是不排队的;
  • SIGCTX_sigaction[NSIG]存放所有信号的控制结构,信号成功安装后将存放到这里;
  • SIGCTX_pringSigQ[NSIG]存放所有因为被屏蔽而不能递送且支持排队的信号,也就是非kil函数发送的信号;
  • SIGCTX_stack指向用户提供的堆栈;
  • SIGCTX_sigwait标示线程等待的信号信息;

最下面3个成员实现了signalfd标准设备,这里不做详细解释。
SylixOS中每一个线程对应了一个信号上下文,信号上下文记录对应了线程的信号信息,如线程等待什么信号,线程屏蔽了什么信号,哪些信号正在排队递送等。

2. 递送信号信息结构

每一种信号在递送到指定线程的时候,都需要一些关键的信息,如信号来源等,下面我们来讲解这种结构的详细信息。

typedef struct {
    LW_LIST_RING          SIGPEND_ringSigQ;                /*  环形链表                    */

    struct siginfo        SIGPEND_siginfo;                 /*  信号相关信息                */
    PLW_CLASS_SIGCONTEXT  SIGPEND_psigctx;                 /*  信号上下文                  */
    UINT                  SIGPEND_uiTimes;                 /*  被阻塞的次数                */

    INT                   SIGPEND_iNotify;                 /*  sigevent.sigev_notify       */
} LW_CLASS_SIGPEND;
  • SIGPEND_ringSigQ同一种信号将可能产生多次,如果是非kill函数发送将由此链表管理;
  • SIGPEND_siginfo包含了信号的信息,如信号名、信号来源、附加信号数据、用户信息等;
  • SIGPEND_psigctx回指向信号上下文结构;
  • SIGPEND_uiTimes信号被屏蔽期间产生了多次;
  • SIGPEND_iNotify信号通知类型,如通知、不通知等。
3. 信号控制信息结构

信号的每一次递送都讲被嵌入到一段堆栈空间中,当线程产生调度时,将处理这些内容,这些内容不但包含了堆栈的返回地址(线程被中断处的地址)还包含了信号的一些信息等,如信号安装函数。

typedef struct {
    PVOID                 SIGCTLMSG_pvStackRet;              /*  跳跃返回堆栈的地址          */
    INT                   SIGCTLMSG_iSchedRet;               /*  信号调度器返回值            */
    INT                   SIGCTLMSG_iKernelSpace;            /*  产生信号是的内核空间情况     */
                                                             /*  信号退出时需要返回之前的状态  */
    sigset_t              SIGCTLMSG_sigsetMask;              /*  信号句柄退出需要恢复的掩码   */
    struct siginfo        SIGCTLMSG_siginfo;                 /*  信号相关信息                */
    errno_t               SIGCTLMSG_iLastErrno;              /*  保存的原始错误号            */
} LW_CLASS_SIGCTLMSG;
  • SIGCTLMSG_pvStackRet包含被信号中断时的地址;
  • SIGCTLMSG_iSchedRet标识调度器是信号中断还是正常调度;
  • SIGCTLMSG_iKernelSpace内核空间情况;
  • SIGCTLMSG_sigsetMask信号之前的屏蔽字;
  • SIGCTLMSG_siginfo信号信息,如信号名、产生源等;
  • SIGCTLMSG_iLastErrno保存之前的errno值。

当信号处理函数完成返回后,内核将通过调用__sigReturn函数返回到被中断的地址处,并且在返回前,总会检查能够运行还没有运行的信号,这样避免了再次的堆栈开销。

4. 信号等待信息结构

下面的结构标识了线程等待信号的情况。

typedef struct __sig_wait {
    sigset_t              SIGWT_sigset;
    struct siginfo        SIGWT_siginfo;
} LW_CLASS_SIGWAIT;
  • SIGWT_sigset线程等待的信号集,1位对应了正在等待的信号;
  • SIGWT_siginfo是等待信号的信息。

sigwait函数、sigwaitinfo函数、sigtimedwait函数将关心这个结构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值