RTthread线程间通信(邮箱,消息队列,信号/软件中断)---03信号(软件中断)源码分析

信号

实际使用看这一个

#if defined(RT_USING_SIGNALS)
    rt_sigset_t     sig_pending;                        /**< the pending signals 记录来了的信号 */
    rt_sigset_t     sig_mask;                           /**< the mask bits of signal 记录屏蔽的信号 */

    rt_sighandler_t *sig_vectors;                       /**< vectors of signal handler 记录处理函数 */
    void            *si_list;                           /**< the signal infor list 挂起的信号的信息链表 */
#endif

线程管理结构体

typedef void (*rt_sighandler_t)(int signo);

处理函数

struct siginfo_node
{
    siginfo_t si;
    struct rt_slist_node list;
};

这一个是用来记录挂起的信号的的信息

信号的处理除了会在这里面显示的位置进行, 还会在切换任务的时候处理

安装

rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler)
{
    rt_base_t level;
    rt_sighandler_t old = RT_NULL;
    rt_thread_t tid = rt_thread_self();
	//看一看是不是有效的值
    if (!sig_valid(signo)) return SIG_ERR;

    level = rt_hw_interrupt_disable();
    if (tid->sig_vectors == RT_NULL)
    {
        //这一个线程之前没有安转过
        rt_thread_alloc_sig(tid);
    }

    if (tid->sig_vectors)
    {
        old = tid->sig_vectors[signo];

        if (handler == SIG_IGN) tid->sig_vectors[signo] = RT_NULL;
        else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler;
        else tid->sig_vectors[signo] = handler;
    }
    rt_hw_interrupt_enable(level);

    return old;
}
void rt_thread_alloc_sig(rt_thread_t tid)
{
    int index;
    rt_base_t level;
    rt_sighandler_t *vectors;
	//获取一个足以记录处理所有信号的函数的数组
    vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX);
    RT_ASSERT(vectors != RT_NULL);
    
    for (index = 0; index < RT_SIG_MAX; index ++)
    {
        //初始化为默认的函数
        vectors[index] = _signal_default_handler;
    }
	//把这一个数组记录在线程里面
    level = rt_hw_interrupt_disable();
    tid->sig_vectors = vectors;
    rt_hw_interrupt_enable(level);
}
//默认的函数
static void _signal_default_handler(int signo)
{
    LOG_I("handled signo[%d] with default action.", signo);
    return ;
}

删除(屏蔽)

//实际上是更新一下线程里面的屏蔽值
void rt_signal_mask(int signo)
{
    rt_base_t level;
    rt_thread_t tid = rt_thread_self();

    level = rt_hw_interrupt_disable();

    tid->sig_mask &= ~sig_mask(signo);

    rt_hw_interrupt_enable(level);
}

解除

void rt_signal_unmask(int signo)
{
    rt_base_t level;
    rt_thread_t tid = rt_thread_self();
    
    level = rt_hw_interrupt_disable();
	//改一下标志
    tid->sig_mask |= sig_mask(signo);

    /* let thread handle pended signals */
    if (tid->sig_mask & tid->sig_pending)
    {
        //有需要处理的标志
        rt_hw_interrupt_enable(level);
        _signal_deliver(tid);
    }
    else
    {
        rt_hw_interrupt_enable(level);
    }
}
//根据要处理的有信号的线程的状态进行分支处理
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
    {
        //这一个任务运行或ready中
        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);
			
            /* 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);//设置一下这一个线程返回以后的处理
            

            rt_hw_interrupt_enable(level);
            LOG_D("signal stack pointer @ 0x%08x", tid->sp);

            /* re-schedule */
            rt_schedule();
        }
        else
        {
            rt_hw_interrupt_enable(level);
        }
    }
}
//这是一个软件中断的线程, 如果需要执行这一个的线程不在runing状态, 会使用一个新的栈空间执行这一个线程
void rt_thread_handle_sig(rt_bool_t clean_state)
{
    rt_base_t level;

    rt_thread_t tid = rt_thread_self();
    struct siginfo_node *si_node;

    level = rt_hw_interrupt_disable();
    if (tid->sig_pending & tid->sig_mask)
    {
        /* if thread is not waiting for signal 等一个信号的话直接返回 */
        if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT))
        {
            //这个时候不是在等一个信号
            while (tid->sig_pending & tid->sig_mask)
            {
                //依次处理信号
                int signo, error;
                rt_sighandler_t handler;
				//获取一个待处理的信号
                si_node = (struct siginfo_node *)tid->si_list;
                if (!si_node) break;

                /* remove this sig info node from list  */
                if (si_node->list.next == RT_NULL)
                    tid->si_list = RT_NULL;//这是最后一个信号
                else
                    tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);//记录下一个信号

                signo   = si_node->si.si_signo;//获取标号
                handler = tid->sig_vectors[signo];//获取处理函数
                tid->sig_pending &= ~sig_mask(signo);//更新挂起的标志
                rt_hw_interrupt_enable(level);

                LOG_D("handle signal: %d, handler 0x%08x", signo, handler);
                if (handler) handler(signo);//执行处理函数

                level = rt_hw_interrupt_disable();
                error = -RT_EINTR;

                rt_mp_free(si_node); /* release this siginfo node 从内存池里面释放 */
                /* set errno in thread tcb */
                tid->error = error;
            }

            /* whether clean signal status */
            //这一个标志需要清除
            if (clean_state == RT_TRUE)
            {
                tid->stat &= ~RT_THREAD_STAT_SIGNAL;
            }
            else
            {
                return;
            }
        }
    }
    rt_hw_interrupt_enable(level);
}
//非当前线程的时候线程返回时候的处理函数(软件中断)
static void _signal_entry(void *parameter)
{
    rt_thread_t tid = rt_thread_self();

    /* handle signal 处理一下信号 */
    rt_thread_handle_sig(RT_FALSE);

    /* return to thread 返回之前的在处理的任务状态 */
    tid->sp = tid->sig_ret;//改变栈
    tid->sig_ret = RT_NULL;

    LOG_D("switch back to: 0x%08x\n", tid->sp);
    tid->stat &= ~RT_THREAD_STAT_SIGNAL;
	//线程处理的里面分析了, 主要是切换一下运行位置以及栈
    rt_hw_context_switch_to((rt_ubase_t)&(tid->sp));
}

发送信号

#define sig_mask(sig_no)    (1u << sig_no)
int rt_thread_kill(rt_thread_t tid, int sig)
{
    siginfo_t si;
    rt_base_t level;
    struct siginfo_node *si_node;
	
    if (!sig_valid(sig)) return -RT_EINVAL;
	
    LOG_I("send signal: %d", sig);
    si.si_signo = sig;
    si.si_code  = SI_USER;
    si.si_value.sival_ptr = RT_NULL;

    level = rt_hw_interrupt_disable();
    if (tid->sig_pending & sig_mask(sig))
    {
        //这一个信号标志已经挂起了, 用这一个新的信息队列覆盖之前的信息
        /* whether already emits this signal? */
        struct rt_slist_node *node;
        struct siginfo_node  *entry;
		//获取挂起的信号的信息链表
        si_node = (struct siginfo_node *)tid->si_list;
        if (si_node)
            node = (struct rt_slist_node *)&si_node->list;
        else
            node = RT_NULL;

        /* update sig info */
        for (; (node) != RT_NULL; node = node->next)
        {
            //遍历当前任务待处理的所有信号信息
            entry = rt_slist_entry(node, struct siginfo_node, list);
            if (entry->si.si_signo == sig)
            {
                //用新的信息覆盖
                memcpy(&(entry->si), &si, sizeof(siginfo_t));
                rt_hw_interrupt_enable(level);
                return 0;
            }
        }
    }
    rt_hw_interrupt_enable(level);
	//这时候是标志没有挂起, 或者挂起了但是没有信息处理的链表项
    //获取一个内存块
    si_node = (struct siginfo_node *) rt_mp_alloc(_rt_siginfo_pool, 0);
    if (si_node)
    {
        rt_slist_init(&(si_node->list));
        //更新一下信息
        memcpy(&(si_node->si), &si, sizeof(siginfo_t));
        level = rt_hw_interrupt_disable();
		//把这个挂入链表里面
        if (tid->si_list)
        {
            struct siginfo_node *si_list;
			//这个里面前面有节点
            si_list = (struct siginfo_node *)tid->si_list;
            rt_slist_append(&(si_list->list), &(si_node->list));
        }
        else
        {
            //前面没有, 这就是第一个
            tid->si_list = si_node;
        }

        /* a new signal 记录一下标志 */
        tid->sig_pending |= sig_mask(sig);

        rt_hw_interrupt_enable(level);
    }
    else
    {
        LOG_E("The allocation of signal info node failed.");
    }

    /* deliver signal to this thread */
    _signal_deliver(tid);

    return RT_EOK;
}
int rt_system_signal_init(void)
{
    //这一个会设置rt_mp_alloc返回的大小
    _rt_siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node));
    if (_rt_siginfo_pool == RT_NULL)
    {
        LOG_E("create memory pool for signal info failed.");
        RT_ASSERT(0);
    }

    return 0;
}

等待信号

这一个实际是一直在等待那一个信号, 那一个信号来之前一直挂起, 不会处理其他信号

int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout)
{
    int ret = RT_EOK;
    rt_base_t   level;
    rt_thread_t tid = rt_thread_self();
    struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL;

    /* current context checking */
    RT_DEBUG_IN_THREAD_CONTEXT;

    /* parameters check */
    if (set == NULL || *set == 0 || si == NULL )
    {
        ret = -RT_EINVAL;
        goto __done_return;
    }

    /* clear siginfo to avoid unknown value 清空一下, 用于记录 */
    memset(si, 0x0, sizeof(rt_siginfo_t));

    level = rt_hw_interrupt_disable();

    /* already pending */
    if (tid->sig_pending & *set) goto __done;

    if (timeout == 0)
    {
        ret = -RT_ETIMEOUT;
        goto __done_int;
    }

    /* suspend self thread 把自己挂起 */
    rt_thread_suspend(tid);
    /* set thread stat as waiting for signal */
    tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT;

    /* start timeout timer */
    if (timeout != RT_WAITING_FOREVER)
    {
        /* reset the timeout of thread timer and start it */
        rt_timer_control(&(tid->thread_timer),
                         RT_TIMER_CTRL_SET_TIME,
                         &timeout);
        rt_timer_start(&(tid->thread_timer));
    }
    rt_hw_interrupt_enable(level);

    /* do thread scheduling */
    rt_schedule();
	//返回, 可能超时或者有信号来了
    level = rt_hw_interrupt_disable();

    /* remove signal waiting flag */
    tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT;

    /* check errno of thread */
    if (tid->error == -RT_ETIMEOUT)
    {
        //是超时
        tid->error = RT_EOK;
        rt_hw_interrupt_enable(level);

        /* timer timeout */
        ret = -RT_ETIMEOUT;
        goto __done_return;
    }

__done:
    //是信号来了
    /* to get the first matched pending signals */
    si_node = (struct siginfo_node *)tid->si_list;
    while (si_node)
    {
        //遍历一下所有的节点
        int signo;

        signo = si_node->si.si_signo;
        if (sig_mask(signo) & *set)
        {
            //是在等的这一个
            *si  = si_node->si;

            LOG_D("sigwait: %d sig raised!", signo);
            
            if (si_prev) si_prev->list.next = si_node->list.next;//这一个信号的链表不在第一个
            else
            {
                //是第一个
                struct siginfo_node *node_next;

                if (si_node->list.next)
                {
                    //不是最后一个
                    node_next = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
                    tid->si_list = node_next;
                }
                else
                {
                    //唯一的信号
                    tid->si_list = RT_NULL;
                }
            }

            /* clear pending */
            tid->sig_pending &= ~sig_mask(signo);//记录为这一个链表处理完了
            rt_mp_free(si_node);//释放一下
            break;
        }

        si_prev = si_node;
        if (si_node->list.next)
        {
            //后面还有, 获取下一个
            si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list);
        }
        else
        {
            si_node = RT_NULL;
        }
     }//while

__done_int:
    rt_hw_interrupt_enable(level);

__done_return:
    return ret;
}

其他

#ifdef RT_USING_SIGNALS
                    /* check stat of thread for signal */
                    level = rt_hw_interrupt_disable();
                    if (rt_current_thread->stat & RT_THREAD_STAT_SIGNAL_PENDING)
                    {
                        extern void rt_thread_handle_sig(rt_bool_t clean_state);

                        rt_current_thread->stat &= ~RT_THREAD_STAT_SIGNAL_PENDING;

                        rt_hw_interrupt_enable(level);

                        /* check signal status 处理信号 */
                        rt_thread_handle_sig(RT_TRUE);
                    }
                    else
                    {
                        rt_hw_interrupt_enable(level);
                    }
#endif

在任务切换的时候rt_schedule里面

你可能感兴趣的:(网络,物联网,笔记,单片机,stm32,51单片机,mcu)