免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6292 | 回复: 14
打印 上一主题 下一主题

信号处理的时机 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-12 10:19 |只看该作者 |倒序浏览
10可用积分
想请教一下信号处理的时机
1、ret_from_sys_call
2、从内核态返回用户态
还有没有?
还想问下 信号处理每次只处理一个信号吗?会不会有信号没有及时处理的情况?

最佳答案

查看完整内容

看了一下linux的代码(linux2.6.25),发现ls说的是有道理的,但是也不完全正确。在一次do_signal()函数的调用中,如果当前正在处理的信号的处理动作是SIG_IGN或者SIG_DFL的话(忽略或者系统默认行为),会一直循环取下一个信号处理。请参见一下函数get_signal_to_deliver()的代码(该函数被do_signal()调用)。但是如果遇到一个信号处理行为不是以上情况的时候(用户为这个信号定义了信号处理函数),就会停止循环。然后get_signa ...

论坛徽章:
0
2 [报告]
发表于 2008-11-12 10:19 |只看该作者
原帖由 eclipse_2 于 2008-11-12 22:35 发表

我看了下源码 感觉还是只处理了一个有自定义信号处理过程的信号,并没有把所有的信号都处理了。
所以 不知道哪儿看的出来一次把进程的所有挂起信号都处理。


看了一下linux的代码(linux2.6.25),发现ls说的是有道理的,但是也不完全正确。
在一次do_signal()函数的调用中,如果当前正在处理的信号的处理动作是SIG_IGN或者SIG_DFL的话(忽略或者系统默认行为),会一直循环取下一个信号处理。请参见一下函数get_signal_to_deliver()的代码(该函数被do_signal()调用)。但是如果遇到一个信号处理行为不是以上情况的时候(用户为这个信号定义了信号处理函数),就会停止循环。然后get_signal_to_deliver()返回,do_signal()调用handle_signal()函数为调用信号处理函数在建立用户栈的内容(信号处理函数要在用户态运行)。最后在do_signal函数返回时就会开始执行这个信号的处理函数了。即执行用户自定义的函数。

可见,对于这种用户自定义的信号处理函数每次调用do_signal()函数时只能处理一个。:)

[ 本帖最后由 greek_zjb 于 2008-11-13 22:32 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2008-11-12 17:35 |只看该作者

Re:

原帖由 eclipse_2 于 2008-11-12 10:19 发表
想请教一下信号处理的时机
1、ret_from_sys_call
2、从内核态返回用户态
还有没有?
还想问下 信号处理每次只处理一个信号吗?会不会有信号没有及时处理的情况?



实际上查看中断处理源代码就可以知道. 当从中断返回时 (Kernel Space=>User Space) , 执行到work_pending, 此时如果需要任务调度,将执行调度程序 schedule, 如果有信号需要处理,则执行 do_notify_resume => do_signal  来处理Pending的Signal.每次都只处理
一个Signal.因为时钟随时都活动,可以保证所有的Signal都可以基本实时被响应.

注意,如果是从Kernel Space发生的中断,将不处理schedule和signal.

以上以i386平台为例.其他平台类似处理.

论坛徽章:
0
4 [报告]
发表于 2008-11-12 21:01 |只看该作者
原帖由 NeilWong 于 2008-11-12 17:35 发表



实际上查看中断处理源代码就可以知道. 当从中断返回时 (Kernel Space=>User Space) , 执行到work_pending, 此时如果需要任务调度,将执行调度程序 schedule, 如果有信号需要处理,则执行 do_notify_resume  ...

从已经看过的代码上 似乎可以看出handle_signal()只执行了一次,就返回了 do_signal(),do_signal()也就返回了。
在handle_signal()函数有setup_frame()函数来对内核堆栈的寄存器进行设置,这样就返回到用户态之前就可以执行执行信号处理程序。
do_signal()会不会重新执行?do_signal()里面有个for循环,它只是用来对信号进行判断用的吧。

论坛徽章:
0
5 [报告]
发表于 2008-11-12 21:44 |只看该作者

回复 #1 eclipse_2 的帖子

信号处理的时机有两处:
1、核外返回到用户态前夕。
2、睡眠进程被唤醒时。

信号处理肯定一次把进程收到的信号处理完。通过信号相应的机制,信号的异步特性,可以肯定一般情况下信号的处理是“很及时的”,而且信号机制经过了很多年的改进,现在叫“可靠信号”了,如果对于实时性不是要求极高的情况下,是OK的。

论坛徽章:
0
6 [报告]
发表于 2008-11-12 22:09 |只看该作者
原帖由 samon_fu 于 2008-11-12 21:44 发表
信号处理的时机有两处:
1、核外返回到用户态前夕。
2、睡眠进程被唤醒时。

信号处理肯定一次把进程收到的信号处理完。通过信号相应的机制,信号的异步特性,可以肯定一般情况下信号的处理是“很及时的”, ...

信号处理一次性把挂起的信号全部处理完?能不能结合代码分析一下,谢谢!

论坛徽章:
0
7 [报告]
发表于 2008-11-12 22:35 |只看该作者
原帖由 samon_fu 于 2008-11-12 21:44 发表
信号处理的时机有两处:
1、核外返回到用户态前夕。
2、睡眠进程被唤醒时。

信号处理肯定一次把进程收到的信号处理完。通过信号相应的机制,信号的异步特性,可以肯定一般情况下信号的处理是“很及时的”, ...

我看了下源码 感觉还是只处理了一个有自定义信号处理过程的信号,并没有把所有的信号都处理了。
所以 不知道哪儿看的出来一次把进程的所有挂起信号都处理。

论坛徽章:
0
8 [报告]
发表于 2008-11-14 00:43 |只看该作者

回复 #6 eclipse_2 的帖子


  1. arch/i386/kernel/signal.c

  2. static void fastcall do_signal(struct pt_regs *regs)
  3. {
  4.     ....
  5.     signr = get_signal_to_deliver(&info, &ka, regs, NULL);
  6.     ...
  7. }

  8. int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
  9.                           struct pt_regs *regs, void *cookie)
  10. {
  11.     ....
  12.     for (;;) {
  13.           ....
  14.     }
  15. }
复制代码


我的理解是这个循环,你看是不是这地方?

论坛徽章:
0
9 [报告]
发表于 2008-11-14 09:28 |只看该作者
原帖由 samon_fu 于 2008-11-14 00:43 发表

arch/i386/kernel/signal.c

static void fastcall do_signal(struct pt_regs *regs)
{
    ....
    signr = get_signal_to_deliver(&info, &ka, regs, NULL);
    ...
}

int get_signal_to_deli ...

我觉得不应该在你说的那个地方吧
这个是我看的代码 虽然是个for循环 但是handler_signal()处理完成后 do_signal()也返回了,进程继续执行。

do_signal()
{
       for (; {
                unsigned long signr;

                spin_lock_irq(&current->sigmask_lock);
                signr = dequeue_signal(&current->blocked, &info);
                spin_unlock_irq(&current->sigmask_lock);

                if (!signr)
                        break;

                if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
                        /* Let the debugger run.  */
                        current->exit_code = signr;
                        current->state = TASK_STOPPED;
                        notify_parent(current, SIGCHLD);
                        schedule();

                        /* We're back.  Did the debugger cancel the sig?  */
                        if (!(signr = current->exit_code))
                                continue;
                        current->exit_code = 0;

                        /* The debugger continued.  Ignore SIGSTOP.  */
                        if (signr == SIGSTOP)
                                continue;

                        /* Update the siginfo structure.  Is this good?  */
                        if (signr != info.si_signo) {
                                info.si_signo = signr;
                                info.si_errno = 0;
                                info.si_code = SI_USER;
                                info.si_pid = current->p_pptr->pid;
                                info.si_uid = current->p_pptr->uid;
                        }

                        /* If the (new) signal is now blocked, requeue it.  */
                        if (sigismember(&current->blocked, signr)) {
                                send_sig_info(signr, &info, current);
                                continue;
                        }
                }

                ka = &current->sig->action[signr-1];
                if (ka->sa.sa_handler == SIG_IGN) {
                        if (signr != SIGCHLD)
                                continue;
                        /* Check for SIGCHLD: it's special.  */
                        while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
                                /* nothing */;
                        continue;
                }

                if (ka->sa.sa_handler == SIG_DFL) {
                        int exit_code = signr;

                        /* Init gets no signals it doesn't want.  */
                        if (current->pid == 1)
                                continue;

                        switch (signr) {
                        case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
                                continue;

                        case SIGTSTP: case SIGTTIN: case SIGTTOU:
                                if (is_orphaned_pgrp(current->pgrp))
                                        continue;
                                /* FALLTHRU */

                        case SIGSTOP: {
                                struct signal_struct *sig;
                                current->state = TASK_STOPPED;
                                current->exit_code = signr;
                                sig = current->p_pptr->sig;
                                if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
                                        notify_parent(current, SIGCHLD);
                                schedule();
                                continue;
                        }

                        case SIGQUIT: case SIGILL: case SIGTRAP:
                        case SIGABRT: case SIGFPE: case SIGSEGV:
                        case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
                                if (do_coredump(signr, regs))
                                        exit_code |= 0x80;
                                /* FALLTHRU */

                        default:
                                sig_exit(signr, exit_code, &info);
                                /* NOTREACHED */
                        }
                }

                /* Reenable any watchpoints before delivering the
                 * signal to user space. The processor register will
                 * have been cleared if the watchpoint triggered
                 * inside the kernel.
                 */
                __asm__("movl %0,%%db7"        : : "r" (current->thread.debugreg[7]));

                /* Whee!  Actually deliver the signal.  */
                handle_signal(signr, ka, &info, oldset, regs);
                return 1;
        }
}

论坛徽章:
0
10 [报告]
发表于 2008-11-14 09:39 |只看该作者
原帖由 samon_fu 于 2008-11-14 00:43 发表

arch/i386/kernel/signal.c

static void fastcall do_signal(struct pt_regs *regs)
{
    ....
    signr = get_signal_to_deliver(&info, &ka, regs, NULL);
    ...
}

int get_signal_to_deli ...



我指的循环就是在get_signal_to_deliver()函数中的for(;{.....}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP