关于信号(signal)处理机制的疑问

发布于 2020-08-07 14:21:39

RT-Thread版本:4.0.3

static void _signal_deliver(rt_thread_t tid)
{
    rt_ubase_t level;

    level = rt_hw_interrupt_disable();

    /* thread is not interested in pended signals */
    if (!(tid->sig_pending & tid->sig_mask))
    {
        rt_hw_interrupt_enable(level);
        return;
    }

    if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
    {
        /* resume thread to handle signal */
        rt_thread_resume(tid);
        /* add signal state */
        tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);

        rt_hw_interrupt_enable(level);

        /* re-schedule */
        rt_schedule();
    }
    else
    {
        if (tid == rt_thread_self())
        {
            /* add signal state */
            tid->stat |= RT_THREAD_STAT_SIGNAL;

            rt_hw_interrupt_enable(level);

            /* do signal action in self thread context */
            if (rt_interrupt_get_nest() == 0)
            {
                rt_thread_handle_sig(RT_TRUE);
            }
        }
        else if (!((tid->stat & RT_THREAD_STAT_SIGNAL_MASK) & RT_THREAD_STAT_SIGNAL))
        {
            /* add signal state */
            tid->stat |= (RT_THREAD_STAT_SIGNAL | RT_THREAD_STAT_SIGNAL_PENDING);

#ifdef RT_USING_SMP
            {
                int cpu_id;

                cpu_id = tid->oncpu;
                if ((cpu_id != RT_CPU_DETACHED) && (cpu_id != rt_hw_cpu_id()))
                {
                    rt_uint32_t cpu_mask;

                    cpu_mask = RT_CPU_MASK ^ (1 << cpu_id);
                    rt_hw_ipi_send(RT_SCHEDULE_IPI, cpu_mask);
                }
            }
#else
            /* point to the signal handle entry */
            tid->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;
            tid->sig_ret = tid->sp;
            tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL,
                                       (void *)((char *)tid->sig_ret - 32), RT_NULL);
#endif

            rt_hw_interrupt_enable(level);
            LOG_D("signal stack pointer <a href="/u/14012" data-type="user" data-id="14012" data-toggle="popover" data-title="">@</a> 0x%08x", tid->sp);

            /* re-schedule */
            rt_schedule();
        }
        else
        {
            rt_hw_interrupt_enable(level);
        }
    }
}

在src/signal.c的_signal_deliver()函数中,根据目标线程的状态分为三种情况:

  1. 目标线程是挂起状态时,恢复成就绪状态,设置信号标志,然后rt_shedule()
  2. 目标线程不是挂起状态,如果目标线程就是当前线程,则直接处理
  3. 目标线程不是挂起状态,如果目标线程不是当前线程,则在目标线程的栈上构建新的context,且通过rt_hw_stack_init把线程entry改为_signal_entry,然后rt_schedule()

我的疑问是:
上述3的情况,为什么要采用构建新的context的方式来处理信号,为什么不采用与情况1相同的处理,也就是通过设置信号标志,然后在目标线程被唤醒的rt_schedule()中来处理?
另外,这里为什么要主动调用一次rt_schedule()?

查看更多

关注者
0
被浏览
264
1 个回答
bernard
bernard 2020-08-07

这个蛮绕的。

建立新的frame来处理,记得主要是为了考虑:

当发送一个signal给就绪、或正在运行的任务,这个时候就需要把它的frame重新构造下,并强行让PC指向过去,然后再切换过去时,就是从这个构造出来的frame上执行。

不过这个,当在多核上时,就又变得超复杂了

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览