Chinaunix首页 | 论坛 | 博客
  • 博客访问: 152898
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-28 14:16
文章分类

全部博文(115)

文章存档

2017年(36)

2016年(79)

我的朋友

分类: LINUX

2017-03-12 17:08:50

原文地址:linux 信号的实现及其使用 作者:zghover

   linux 内核信号机制的实现及其使用

1, 信号

*信号的作用
.让进程知道已经发生了一个特定的事件
.强迫进程执行它自己代码中的信号处理程序

*实时信号和常规信号
POSIX引入了一类新的信号,叫实时信号,在linux中它们的编码范围是32-64。 它们与常规信号的不同之处在于:
.实时信号必须排队以便发送的多个信号都能被接受到
.常规信号不需要排队,若一个常规信号被发送多次,那么只有其中一个发送到接受进程。

*信号的特点
.信号可以随时发送给一个状态不可预知的进程。
.发送给非运行状态的进程的信号必须由内核保存,知道进程恢复运行。
.阻塞一个信号要求一个信号的传递延迟,直到最后接触阻塞,这使得该信号产生一段时间后才能对其进行传递。

*信号的产生和传递
.信号的产生:内核更新目标进程的数据结构,以表示一个新的信号已经被发送。
.信号的传递:内核强迫进程通过以下方式对信号做出动作:或改变目标进程的执行状态,或开始执行一个特定的信号处理函数,或两者同时进行。
.挂起信号:已经产生但是还没有被传递的信号。
.在执行一个信号的处理函数时,内核会自动阻塞该信号,直到处理函数结束。

*信号的阻塞和忽略
.信号的阻塞:该信号不被传递,只有在信号被解除阻塞后才传递它。
.忽略信号:一个被忽略的信号总是被传递,但没有进一步的操作。
.SIGKILL,SIGSTOP信号不可以被显示的忽略,捕获或阻塞。

*信号和线程
.信号处理函数必须在多线程应用的所有线程之间共享;但每个线程可以有自己的信号挂起掩码和阻塞信号掩码。
.kill()和sigqueue()必须向所有的多线程应用,而不是某个特殊的线程发送信号。
.若向多线程应用程序发送了一个致命信号,那么内核将杀死该应用的所有线程,而不只是其中一个线程。

 


2, 数据结构


// 进程秒数符中信号相关的数据结构
struct task_struct {
...
/* signal handlers */
    struct signal_struct *signal; //进程信号描述指针
    struct sighand_struct *sighand; //进程信号处理程序描述符指针

    sigset_t blocked, real_blocked; //被阻塞的信号掩码,和被阻塞的临时掩码
    struct sigpending pending; //存放私有挂起信号的结构

    unsigned long sas_ss_sp; //信号处理函数备用堆栈地址
    size_t sas_ss_size;  //信号处理函备用堆栈大小
    int (*notifier)(void *priv);
    void *notifier_data;
    sigset_t *notifier_mask;
   
    void *security;
    struct audit_context *audit_context;
...
}


// 1-32 表示常规信号,32-64表示实时信号
typedef struct {
    unsigned long sig[_NSIG_WORDS];
} sigset_t;


//信号描述符结构
struct signal_struct {
    atomic_t        count; //使用计数
    atomic_t        live; //线程组中活动线程的数量

    wait_queue_head_t   wait_chldexit;  /* for wait4() */ 系统中调用wait4中睡眠的进程的等待队列

    /* current thread group signal load-balancing target: */
    task_t          *curr_target;

    /* shared signal handling: */
    struct sigpending   shared_pending; //存放共享挂起信号的结构

    /* thread group exit support */
    int         group_exit_code; //线程组的进程终止代码
    /* overloaded:
     * - notify group_exit_task when ->count is equal to notify_count
     * - everyone except group_exit_task is stopped during signal delivery
     *   of fatal signals, group_exit_task processes the signal.
     */
    struct task_struct  *group_exit_task;
    int         notify_count;

    /* thread group stop support, overloads group_exit_code too */
    int         group_stop_count;
    unsigned int        flags; /* see SIGNAL_* flags below */

    /* POSIX.1b Interval Timers */
    struct list_head posix_timers;

    /* job control IDs */
    pid_t pgrp;
    pid_t tty_old_pgrp;
    pid_t session;
    /* boolean value for session group leader */
    int leader;

    struct tty_struct *tty; /* NULL if no tty */

    /*
     * Cumulative resource counters for dead threads in the group,
     * and for reaped dead child processes forked by this group.
     * Live threads maintain their own counters and add to these
     * in __exit_signal, except for the group leader.
     */
    cputime_t utime, stime, cutime, cstime;
    unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
    unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;

    /*
     * We don't bother to synchronize most readers of this at all,
     * because there is no reader checking a limit that actually needs
     * to get both rlim_cur and rlim_max atomically, and either one
     * alone is a single word that can safely be read normally.
     * getrlimit/setrlimit use task_lock(current->group_leader) to
     * protect this instead of the siglock, because they really
     * have no need to disable irqs.
     */
    struct rlimit rlim[RLIM_NLIMITS];
};

//信号处理结构
struct sighand_struct {
    atomic_t        count;
    struct k_sigaction  action[_NSIG];
    spinlock_t      siglock;
};


struct sigaction {
    __sighandler_t sa_handler; //信号处理函数,参数必须是整形数,信号编号
    unsigned long sa_flags; //标志位,表示怎么处理信号
    __sigrestore_t sa_restorer;
    sigset_t sa_mask;       /* mask last for extensibility */ //运行信号处理程序时要屏蔽的信号
};

struct k_sigaction {
    struct sigaction sa;
};


/* 
 * Real Time signals may be queued.
 */
//被阻塞信号队列结点
struct sigqueue {
    struct list_head list;
    spinlock_t *lock;
    int flags;
    siginfo_t info;
    struct user_struct *user;
}; 

/* flags values. */
#define SIGQUEUE_PREALLOC   1
   
//信号阻塞队列
struct sigpending {
    struct list_head list; //阻塞信号链表头,是sigqueue结构的队列
    sigset_t signal; //阻塞信号位图
};
   

/* Type of a signal handler.  */
typedef void __signalfn_t(int);
typedef __signalfn_t __user *__sighandler_t;

typedef void __restorefn_t(void);
typedef __restorefn_t __user *__sigrestore_t;

#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
#define SIG_ERR ((__sighandler_t)-1)    /* error return from signal */

 

 


typedef struct siginfo {
    int si_signo;
    int si_errno;
    int si_code;

    union {
        int _pad[SI_PAD_SIZE];

        /* kill() */
        struct {
            pid_t _pid;     /* sender's pid */
            __ARCH_SI_UID_T _uid;   /* sender's uid */
        } _kill;

        /* POSIX.1b timers */
        struct {
            timer_t _tid;       /* timer id */
            int _overrun;       /* overrun count */
            char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];
            sigval_t _sigval;   /* same as below */
            int _sys_private;       /* not to be passed to user */
        } _timer;

        /* POSIX.1b signals */
        struct {
            pid_t _pid;     /* sender's pid */
            __ARCH_SI_UID_T _uid;   /* sender's uid */
            sigval_t _sigval;
        } _rt;

        /* SIGCHLD */
        struct {
            pid_t _pid;     /* which child */
            __ARCH_SI_UID_T _uid;   /* sender's uid */
            int _status;        /* exit code */
            clock_t _utime;
            clock_t _stime;
        } _sigchld;

        /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
        struct {
            void __user *_addr; /* faulting insn/memory ref. */
#ifdef __ARCH_SI_TRAPNO
            int _trapno;    /* TRAP # which caused the signal */
#endif
        } _sigfault;

        /* SIGPOLL */
        struct {
            __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
            int _fd;
        } _sigpoll;
    } _sifields;
} siginfo_t;

 

3, 实现分析

 

 


参考资料:
 《ulk》
 《lsph》

 

阅读(1112) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~