Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15530269
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2008-09-12 17:02:50

浅析signal机制在alarm应用程序和内核程序的交互对应关系和程序设计注意事项

//========================================================
//lib库中的函数
struct sigaction {
    __sighandler_t sa_handler;
    unsigned long sa_flags;
    __sigrestore_t sa_restorer;
    sigset_t sa_mask;        /* mask last for extensibility */
};

static __inline__ __sighandler_t signal(int s, __sighandler_t f)
{
    return bsd_signal(s,f);
}

__sighandler_t bsd_signal(int signum, __sighandler_t handler)
{
  return _signal(signum, handler, SA_RESTART);
}

static __sighandler_t
_signal(int signum, __sighandler_t handler, int flags)
{
    struct sigaction sa;
    __sighandler_t result = SIG_ERR;

    sigemptyset( &sa.sa_mask );

    sa.sa_handler = handler;
    sa.sa_flags = flags;

    if ( !sigaction( signum, &sa, &sa ) )//执行调用号__NR_sigaction对应的系统调用
//对应kernel的sys_sigaction
        result = (__sighandler_t) sa.sa_handler;

    return result;
}

static __inline__ int sigemptyset(sigset_t *set)
{
    memset(set, 0, sizeof *set);
    return 0;
}


//========================================================
//arm-kernel中的系统调用具体实现
asmlinkage int
sys_sigaction(int sig, const struct old_sigaction __user *act,
     struct old_sigaction __user *oact)
{
    struct k_sigaction new_ka, old_ka;
    int ret;

    if (act) {
        old_sigset_t mask;
        if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
         __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
         __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
            return -EFAULT;
        __get_user(new_ka.sa.sa_flags, &act->sa_flags);
        __get_user(mask, &act->sa_mask);
        siginitset(&new_ka.sa.sa_mask, mask);
    }

    ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

    if (!ret && oact) {
        if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
         __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
         __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
            return -EFAULT;
        __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
        __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
    }

    return ret;
}

int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{
    struct k_sigaction *k;
    sigset_t mask;

    if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
        return -EINVAL;

    k = &current->sighand->action[sig-1];
//这就是我们的用户空间的应用程序对应的内核线程current对应的sighand->action集[luther.gliethttp].
//对于某个signum同时只能有一个k_sigaction来控制,并没有实现为链表方式.
    spin_lock_irq(&current->sighand->siglock);
    if (oact)
        *oact = *k;

    if (act) {
        sigdelsetmask(&act->sa.sa_mask,
             sigmask(SIGKILL) | sigmask(SIGSTOP));
//不论如何kernel将屏蔽掉用户程序企图设置SIGKILL和SIGSTOP,进而不让kernel杀死自己的设置[luther.gliethttp].
        *k = *act;//覆盖current->sighand->action[sig-1]中原有内容,并没有实现为链表方式.
        /*
         * POSIX 3.3.1.3:
         * "Setting a signal action to SIG_IGN for a signal that is
         * pending shall cause the pending signal to be discarded,
         * whether or not it is blocked."
         *
         * "Setting a signal action to SIG_DFL for a signal that is
         * pending and whose default action is to ignore the signal
         * (for example, SIGCHLD), shall cause the pending signal to
         * be discarded, whether or not it is blocked"
         */

        if (act->sa.sa_handler == SIG_IGN ||
         (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) {
            struct task_struct *t = current;
            sigemptyset(&mask);
            sigaddset(&mask, sig);
            rm_from_queue_full(&mask, &t->signal->shared_pending);
            do {
                rm_from_queue_full(&mask, &t->pending);
                t = next_thread(t);
            } while (t != current);
        }
    }

    spin_unlock_irq(&current->sighand->siglock);
    return 0;
}
#define SIGALRM        14
好了已经把alarm对应的signal放入了current->sighand->action[SIGALRM-1].
那什么时候会调用current->sighand->action[SIGALRM-1]中的方法呢?让我们继续研究研究,

sys_rt_sigsuspend=>do_signal
do_notify_resume=>do_signal
sys_sigsuspend=>do_signal
=>do_signal
=>handle_signal
handle_signal=>setup_rt_frame=>setup_return
handle_signal=>setup_frame=>setup_return
=>setup_return
=>


arch/arm/kernel/entry-common.S
....
sys_rt_sigsuspend_wrapper:
        add    r2, sp, #S_OFF
        b    sys_rt_sigsuspend
....
work_pending:
    tst    r1, #_TIF_NEED_RESCHED
    bne    work_resched
    tst    r1, #_TIF_SIGPENDING
    beq    no_work_pending
    mov    r0, sp                @ 'regs'
    mov    r2, why                @ 'syscall'
    bl    do_notify_resume //这里会调用
    b    ret_slow_syscall    @ Check work again
....
sys_sigsuspend_wrapper:
        add    r3, sp, #S_OFF
        b    sys_sigsuspend
....

static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
     siginfo_t *info, sigset_t *oldset,
     struct pt_regs * regs, int syscall)
{
    struct thread_info *thread = current_thread_info();
    struct task_struct *tsk = current;
    int usig = sig;
    int ret;

    /*
     * If we were from a system call, check for system call restarting...
     */

    if (syscall) {
        switch (regs->ARM_r0) {
        case -ERESTART_RESTARTBLOCK:
        case -ERESTARTNOHAND:
            regs->ARM_r0 = -EINTR;
            break;
        case -ERESTARTSYS:
            if (!(ka->sa.sa_flags & SA_RESTART)) {
                regs->ARM_r0 = -EINTR;
                break;
            }
            /* fallthrough */
        case -ERESTARTNOINTR:
            restart_syscall(regs);
        }
    }

    /*
     * translate the signal
     */

    if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
        usig = thread->exec_domain->signal_invmap[usig];

    /*
     * Set up the stack frame
     */

    if (ka->sa.sa_flags & SA_SIGINFO)
        ret = setup_rt_frame(usig, ka, info, oldset, regs);
    else
        ret = setup_frame(usig, ka, oldset, regs);

    /*
     * Check that the resulting registers are actually sane.
     */

    ret |= !valid_user_regs(regs);

    if (ret != 0) {
        force_sigsegv(sig, tsk);
        return;
    }

    /*
     * Block the signal if we were successful.
     */

    spin_lock_irq(&tsk->sighand->siglock);
    sigorsets(&tsk->blocked, &tsk->blocked,
         &ka->sa.sa_mask);
    if (!(ka->sa.sa_flags & SA_NODEFER))
        sigaddset(&tsk->blocked, sig);
    recalc_sigpending();
    spin_unlock_irq(&tsk->sighand->siglock);

}


static int
setup_return(struct pt_regs *regs, struct k_sigaction *ka,
     unsigned long __user *rc, void __user *frame, int usig)
{
    unsigned long handler = (unsigned long)ka->sa.sa_handler;//这就是我们alarm登记的handler处理函数[luther.gliethttp]
    unsigned long retcode;
    int thumb = 0;
    unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;

    /*
     * Maybe we need to deliver a 32-bit signal to a 26-bit task.
     */

    if (ka->sa.sa_flags & SA_THIRTYTWO)
        cpsr = (cpsr & ~MODE_MASK) | USR_MODE;

#ifdef CONFIG_ARM_THUMB
    if (elf_hwcap & HWCAP_THUMB) {
        /*
         * The LSB of the handler determines if we're going to
         * be using THUMB or ARM mode for this signal handler.
         */

        thumb = handler & 1;

        if (thumb)
            cpsr |= PSR_T_BIT;
        else
            cpsr &= ~PSR_T_BIT;
    }
#endif

    if (ka->sa.sa_flags & SA_RESTORER) {
        retcode = (unsigned long)ka->sa.sa_restorer;
    } else {
        unsigned int idx = thumb << 1;

        if (ka->sa.sa_flags & SA_SIGINFO)
            idx += 3;

        if (__put_user(sigreturn_codes[idx], rc) ||
         __put_user(sigreturn_codes[idx+1], rc+1))
            return 1;

        if (cpsr & MODE32_BIT) {
            /*
             * 32-bit code can use the new high-page
             * signal return code support.
             */

            retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
        } else {
            /*
             * Ensure that the instruction cache sees
             * the return code written onto the stack.
             */

            flush_icache_range((unsigned long)rc,
                     (unsigned long)(rc + 2));

            retcode = ((unsigned long)rc) + thumb;
        }
    }

    regs->ARM_r0 = usig;
    regs->ARM_sp = (unsigned long)frame;
    regs->ARM_lr = retcode;//这是sa_handler处理函数执行完成之后,返回的地址
    regs->ARM_pc = handler;
//这就是本次信号触发之后,从内核空间返回用户空间的地址指针,也就是将会返回到我们的用户程序登记注册的处理函数,
//而不是while()可能执行到的位置了,即便在处理alarm_sa_handler处理函数的时候被kernel schedule出去了,但是因为
//alarm_sa_handler处理函数就是当前用户空间处理所在pc,也就是kernel认为的应用程序执行所到处,故当又被kernel schedule
//回到该用户应用程序之后,会继续执行未执行完的alarm_sa_handler处理函数,
//这也就是直接能够剥夺while主处理流程而去执行alarm_sa_handler处理函数的直接原因所在了[luther.gliethttp].
//所以alarm_sa_handler函数中就不可能采用同步机制mutex,sem之类,与while()处理部分进行同步,因为alarm_sa_handler
//并不是一个独立的thread,所以使用signal进行程序设计时,需要我们大家多多注意,signal的这个特性,
//避免用户空间应用程序出现莫名其妙的问题[luther.gliethttp].
    regs->ARM_cpsr = cpsr;

    return 0;
}

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