Rtthread线程源码分析

Rtthread线程源码分析

/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique
 * @param entry the entry function of thread
 * @param parameter the parameter of thread enter function
 * @param stack_size the size of thread stack
 * @param priority the priority of thread
 * @param tick the time slice if there are same priority thread
 *
 * @return the created thread object
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)
{
    struct rt_thread *thread;
    void *stack_start;
    //1. 创建一个RT_Object_Class_Thread类型的objectd对象
    thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
                                                    name);
    if (thread == RT_NULL)
        return RT_NULL;
    //2. 申请分配线程栈空间
    stack_start = (void *)RT_KERNEL_MALLOC(stack_size);
    if (stack_start == RT_NULL)
    {
        /* allocate stack failure */
        //失败需要先删除该object并释放内存
        rt_object_delete((rt_object_t)thread);

        return RT_NULL;
    }
    //3. 调用_rt_thread_init
    _rt_thread_init(thread,
                    name,
                    entry,
                    parameter,
                    stack_start,
                    stack_size,
                    priority,
                    tick);

    return thread;
}

static rt_err_t _rt_thread_init(struct rt_thread *thread,
                                const char       *name,
                                void (*entry)(void *parameter),
                                void             *parameter,
                                void             *stack_start,
                                rt_uint32_t       stack_size,
                                rt_uint8_t        priority,
                                rt_uint32_t       tick)
{
    /* init thread list */
    rt_list_init(&(thread->tlist));
    // 1. 指定线程入口函数和参数
    thread->entry = (void *)entry;
    thread->parameter = parameter;

    /* stack init */
    //2. 线程结构体初始化
    thread->stack_addr = stack_start;
    thread->stack_size = stack_size;

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
#ifdef ARCH_CPU_STACK_GROWS_UPWARD //我们一般使用满减栈,所以该宏不定义
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr),
                                          (void *)rt_thread_exit);
#else //走else
    // 3. 调用rt_hw_stack_init 初始化栈,栈顶的值为 【栈首地址 + 栈大小 - 4】
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
       (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
                                                                     (void *)rt_thread_exit);
#endif

    /* priority init */
    RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);
    //初始化thread优先级成员
    thread->init_priority    = priority;
    thread->current_priority = priority;

    thread->number_mask = 0;
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number = 0;
    thread->high_mask = 0;
#endif

    /* tick init */
    thread->init_tick      = tick;
    thread->remaining_tick = tick;

    /* error and flags */
    thread->error = RT_EOK;
    thread->stat  = RT_THREAD_INIT;

    /* initialize cleanup function and user data */
    thread->cleanup   = 0;
    thread->user_data = 0;

    /* initialize thread timer */
    //初始化线程timer
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

    RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread));

    return RT_EOK;
}
rt_uint8_t *rt_hw_stack_init(void       *tentry,
                             void       *parameter,
                             rt_uint8_t *stack_addr,
                             void       *texit)
{
    struct stack_frame *stack_frame;
    rt_uint8_t         *stk;
    unsigned long       i;

    stk  = stack_addr + sizeof(rt_uint32_t);//传进来的stack_addr 减去了4,所以这里加上4
    stk  = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);//向下8对齐,考虑到64bit平台
    stk -= sizeof(struct stack_frame);//偏移到stack_frame的首地址

    stack_frame = (struct stack_frame *)stk;

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }
    //这些寄存器是线程调度时自动加载到寄存器中去的,剩下的r4-r11需要手动加载
    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; /* r0 : argument */
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    stack_frame->exception_stack_frame.r12 = 0;                        /* r12 */
    /*线程函数退出时会执行,退出时会将该函数当作返回的地址*/
    stack_frame->exception_stack_frame.lr  = (unsigned long)texit;     /* lr */
    stack_frame->exception_stack_frame.pc  = (unsigned long)tentry;    /* entry point, pc */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR XPSR bit24 为1,使用thumb指令集*/

#if USE_FPU
    stack_frame->flag = 0;
#endif /* USE_FPU */

    /* return task's current stack address */
    return stk;
}

栈初始化后的布局
请添加图片描述

rt_thread_startup

rt_thread_startup函数主要作用是将当前init完成的线程从SUSPEND状态切换到READY状态,
将该thread从tlist链表中移除,插入到就绪链表。

/**
 * This function will start a thread and put it to system ready queue
 *
 * @param thread the thread to be started
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)
{
    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* set current priority to initialize priority */
    thread->current_priority = thread->init_priority;

    /* calculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
    thread->number      = thread->current_priority >> 3;            /* 5bit */
    thread->number_mask = 1L << thread->number;
    thread->high_mask   = 1L << (thread->current_priority & 0x07);  /* 3bit */
#else
    thread->number_mask = 1L << thread->current_priority;//计算当前number_mask
#endif

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n",
                                   thread->name, thread->init_priority));
    /* change thread stat */
    thread->stat = RT_THREAD_SUSPEND; //将init状态切换到SUSPEND状态
    /* then resume it */
    rt_thread_resume(thread); //调用resume将该thread切换到ready状态
    if (rt_thread_self() != RT_NULL)//开第一个系统线程的时候不会走这里
    {
        /* do a scheduling */
        rt_schedule();
    }

    return RT_EOK;
}
/**
 * This function will resume a thread and put it to system ready queue.
 *
 * @param thread the thread to be resumed
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_resume(rt_thread_t thread)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume:  %s\n", thread->name));

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n",
                                       thread->stat));
        return -RT_ERROR;
    }

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* remove from suspend list */
    //将该tlist从thread中移除
    rt_list_remove(&(thread->tlist));

    rt_timer_stop(&thread->thread_timer);

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* insert to schedule ready list */
    //将该线程插入ready list,将tlist挂载到rt_thread_priority_table中去
    rt_schedule_insert_thread(thread);

    RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread));
    return RT_EOK;
}

/**
 * @ingroup SystemInit
 * This function will startup scheduler. It will select one thread
 * with the highest priority level, then switch to it.
 */
void rt_system_scheduler_start(void)
{
    register struct rt_thread *to_thread;
    register rt_ubase_t highest_ready_priority;

#if RT_THREAD_PRIORITY_MAX > 32
    register rt_ubase_t number;

    number = __rt_ffs(rt_thread_ready_priority_group) - 1;
    highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#else
    //快速查找最高优先级线程,时间复杂度固定的,RTOS系统关键部分
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#endif

    /* get switch to thread */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);

    rt_current_thread = to_thread;

    /* switch to new thread */
    //线程调度实现:
    rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

    /* never come back */
}
/*
 * void rt_hw_context_switch_to(rt_uint32 to);
 * r0 --> to
 */
.global rt_hw_context_switch_to
.type rt_hw_context_switch_to, %function
rt_hw_context_switch_to:
    //将rt_hw_context_switch_to的参数(rt_uint32_t)&to_thread->sp sp的地址保存到rt_interrupt_to_thread
    LDR r1, =rt_interrupt_to_thread
    STR r0, [r1]

#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    /* CLEAR CONTROL.FPCA */
    MRS     r2, CONTROL         /* read */
    BIC     r2, #0x04           /* modify */
    MSR     CONTROL, r2         /* write-back */
#endif

    /* set from thread to 0 */
    //第一次切换线程,无需保存上文,rt_interrupt_from_thread写0
    LDR r1, =rt_interrupt_from_thread
    MOV r0, #0x0
    STR r0, [r1]

    /* set interrupt flag to 1 */
    //将rt_thread_switch_interrupt_flag 置1
    LDR     r1, =rt_thread_switch_interrupt_flag
    MOV     r0, #1
    STR     r0, [r1]

    /* set the PendSV and SysTick exception priority */
    //将systick和pendsv优先级都设置为最低
    LDR r0, =NVIC_SYSPRI2
    LDR r1, =NVIC_PENDSV_PRI
    LDR.W   r2, [r0,#0x00]       /* read       */
    ORR     r1,r1,r2             /* modify     */
    STR     r1, [r0]             /* write-back */
    
    //写28bit 置1将悬起Pendsv中断,如果当前没有其他中断发生,那么将进入pendsv handler
    LDR r0, =NVIC_INT_CTRL      /* trigger the PendSV exception (causes context switch) */
    LDR r1, =NVIC_PENDSVSET
    STR r1, [r0]

    /* restore MSP */
    LDR     r0, =SCB_VTOR   //获取SCB_VTOR寄存器的地址
    LDR     r0, [r0]        //获取SCB_VTOR寄存器的值,该值保存向量表的地址
    LDR     r0, [r0]        //获取向量表偏移为0的值,即为MSP指针(启动文件中向量表的排布)
    NOP
    MSR     msp, r0         //复位MSP

    /* enable interrupts at processor level */
    CPSIE   F               //使能中断和异常
    CPSIE   I

    /* never reach here! */

悬起一个pendsv异常后,在没有其他中断或者异常发生的时候,就会进入pendsv中切换上下文:

/* r0 --> switch from thread stack
 * r1 --> switch to thread stack
 * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
 */
.global PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:
    /* disable interrupt to protect context switch */
    //上下文切换之前先要禁用中断,保证切换不被打断
    MRS r2, PRIMASK
    CPSID   I

    /* get rt_thread_switch_interrupt_flag */
    //判断rt_thread_switch_interrupt_flag,为0则退出pendsv handler
    LDR r0, =rt_thread_switch_interrupt_flag
    LDR r1, [r0]
    CBZ r1, pendsv_exit         /* pendsv already handled */

    /* clear rt_thread_switch_interrupt_flag to 0 */
    //清理rt_thread_switch_interrupt_flag 
    MOV r1, #0x00
    STR r1, [r0]

    //判断是否需要保存上文,启动第一个线程的时候不需要保存上文。
    LDR r0, =rt_interrupt_from_thread
    LDR r1, [r0]
    CBZ r1, switch_to_thread    /* skip register save at the first time */

    //保存上文:获取上文psp的值
    MRS r1, psp                 /* get from thread stack pointer */
    
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    TST     lr, #0x10           /* if(!EXC_RETURN[4]) */
    VSTMDBEQ r1!, {d8 - d15}    /* push FPU register s16~s31 */
#endif
    //将R4-R11手动保存到栈中,其他寄存器都已经由硬件自动入栈保存了。
    //相当于: r1 -= 4*(11 - 4) for(i = 0; i < 11 - 4; i++) r4 -> r11 入栈
    STMFD   r1!, {r4 - r11}     /* push r4 - r11 register */

#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    MOV     r4, #0x00           /* flag = 0 */

    TST     lr, #0x10           /* if(!EXC_RETURN[4]) */
    MOVEQ   r4, #0x01           /* flag = 1 */

    STMFD   r1!, {r4}           /* push flag */
#endif
    //更新栈变量的值为 当前栈指针指向的栈地址
    LDR r0, [r0]
    STR r1, [r0]                /* update from thread stack pointer */

//下文切换:
switch_to_thread:
    //获取栈指针的值
    LDR r1, =rt_interrupt_to_thread
    LDR r1, [r1]
    LDR r1, [r1]                /* load thread stack pointer */

#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    LDMFD   r1!, {r3}           /* pop flag */
#endif
    //手动将r4-r11出栈,写入对应的寄存器中。
    LDMFD   r1!, {r4 - r11}     /* pop r4 - r11 register */

#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    CMP     r3,  #0             /* if(flag_r3 != 0) */
    VLDMIANE  r1!, {d8 - d15}   /* pop FPU register s16~s31 */
#endif
    //将r1(当前栈地址) 写入psp, 在异常返回时硬件会主动Load r0 r1...这些寄存器
    MSR psp, r1                 /* update stack pointer */

#if defined (__VFP_FP__) && !defined(__SOFTFP__)
    ORR     lr, lr, #0x10       /* lr |=  (1 << 4), clean FPCA. */
    CMP     r3,  #0             /* if(flag_r3 != 0) */
    BICNE   lr, lr, #0x10       /* lr &= ~(1 << 4), set FPCA. */
#endif

pendsv_exit:
    /* restore interrupt */
    MSR PRIMASK, r2
    //在进入异常服务程序后,LR的值被自动更新为特殊的EXC_RETURN,这
    //是一个高28位全为1的值,只有[3:0]的值有特殊含义
    //bit2 == 1 从进程堆栈中做出栈操作,返回后使用PSP
    ORR lr, lr, #0x04
    BX  lr

到这里线程main线程就会开始启动了,启动之后,systick定时器会在各个线程时间片耗尽之后触发pendsv切换
线程。

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}
/**
 * This function will notify kernel there is one tick passed. Normally,
 * this function is invoked by clock ISR.
 */
void rt_tick_increase(void)
{
    struct rt_thread *thread;

    /* increase the global tick */
    ++ rt_tick;//计时器+1 单位ms

    /* check time slice */
    thread = rt_thread_self();//获取当前线程

    -- thread->remaining_tick;//线程时间片-1
    if (thread->remaining_tick == 0)//时间片耗尽
    {
        /* change to initialized tick */
        thread->remaining_tick = thread->init_tick;//时间片重新赋值

        /* yield */
        rt_thread_yield();//线程挂起
    }

    /* check timer */
    rt_timer_check();
}
/**
 * This function will let current thread yield processor, and scheduler will
 * choose a highest thread to run. After yield processor, the current thread
 * is still in READY state.
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_yield(void)
{
    register rt_base_t level;
    struct rt_thread *thread;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /* set to current thread */
    thread = rt_current_thread;

    /* if the thread stat is READY and on ready queue list */
    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY &&
        thread->tlist.next != thread->tlist.prev)//线程时ready状态并且挂载在就绪表中
    {
        /* remove thread from thread list */
        rt_list_remove(&(thread->tlist));

        /* put thread to end of ready queue */
        rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                              &(thread->tlist));//将当前线程插入末尾

        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        rt_schedule();//开启线程调度

        return RT_EOK;
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

/**
 * This function will perform one schedule. It will select one thread
 * with the highest priority level, then switch to it.
 */
void rt_schedule(void)
{
    rt_base_t level;
    struct rt_thread *to_thread;
    struct rt_thread *from_thread;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /* check the scheduler is enabled or not */
    if (rt_scheduler_lock_nest == 0)//rt_scheduler_lock_nest 用来锁住rt_schedule,确保有些场景不能被打断
    {
        register rt_ubase_t highest_ready_priority;

#if RT_THREAD_PRIORITY_MAX <= 32
        //获取就绪表中优先级最高的线程下标
        highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
#else
        register rt_ubase_t number;

        number = __rt_ffs(rt_thread_ready_priority_group) - 1;
        highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1;
#endif

        /* get switch to thread */
        //获取将要切换的线程实例
        to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                                  struct rt_thread,
                                  tlist);

        /* if the destination thread is not the same as current thread */
        if (to_thread != rt_current_thread)
        {
            rt_current_priority = (rt_uint8_t)highest_ready_priority;
            from_thread         = rt_current_thread;
            rt_current_thread   = to_thread;

            RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread));

            /* switch to new thread */
            RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
                         ("[%d]switch to priority#%d "
                          "thread:%.*s(sp:0x%p), "
                          "from thread:%.*s(sp: 0x%p)\n",
                          rt_interrupt_nest, highest_ready_priority,
                          RT_NAME_MAX, to_thread->name, to_thread->sp,
                          RT_NAME_MAX, from_thread->name, from_thread->sp));

#ifdef RT_USING_OVERFLOW_CHECK
            _rt_scheduler_stack_check(to_thread);
#endif

            if (rt_interrupt_nest == 0)
            {
                rt_hw_context_switch((rt_ubase_t)&from_thread->sp,
                                     (rt_ubase_t)&to_thread->sp);

                /* enable interrupt */
                rt_hw_interrupt_enable(level);

                return ;
            }
            else
            {
                RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n"));

                rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
                                               (rt_ubase_t)&to_thread->sp);
            }
        }
    }

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}
/*
 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
 * r0 --> from
 * r1 --> to
 */
.global rt_hw_context_switch_interrupt
.type rt_hw_context_switch_interrupt, %function
.global rt_hw_context_switch
.type rt_hw_context_switch, %function

rt_hw_context_switch_interrupt:
rt_hw_context_switch:
    /* set rt_thread_switch_interrupt_flag to 1 */
    LDR     r2, =rt_thread_switch_interrupt_flag
    LDR     r3, [r2]
    CMP     r3, #1
    BEQ     _reswitch //判断rt_thread_switch_interrupt_flag是否为1,为1说明上一次线程切换没有完成,跳转到_reswitch 
    MOV     r3, #1 //rt_thread_switch_interrupt_flag 为0,将其置1
    STR     r3, [r2]

    LDR     r2, =rt_interrupt_from_thread   /* set rt_interrupt_from_thread */
    STR     r0, [r2] //将上文中的栈指针的地址保存到rt_interrupt_from_thread   

_reswitch:
    LDR     r2, =rt_interrupt_to_thread     /* set rt_interrupt_to_thread */
    STR     r1, [r2]  //将下文中的栈指针地址保存到rt_interrupt_to_thread     

    LDR r0, =NVIC_INT_CTRL              /* trigger the PendSV exception (causes context switch) */
    LDR r1, =NVIC_PENDSVSET        
    STR r1, [r0]            //悬起pendsv
    BX  LR //异常返回

线程退出

当线程函数退出时会将lr的值load到pc中,因为在初始化线程栈时,LR的值我们设置的是rt_thread_exit,所以
线程函数退出时会call这个函数。

void rt_thread_exit(void)
{
    struct rt_thread *thread;
    register rt_base_t level;

    /* get current thread */
    thread = rt_current_thread;//获取当前退出的线程

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    _thread_cleanup_execute(thread);//如果有指定该线程的清理函数,则会调用该线程的清理函数

    /* remove from schedule */
    rt_schedule_remove_thread(thread);//将该线程从就绪表中移除
    /* change stat */
    thread->stat = RT_THREAD_CLOSE;//设置线程状态为close

    /* remove it from timer list */
    rt_timer_detach(&thread->thread_timer);//线程时间分离

    if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)//判断是否为系统线程
    {
        rt_object_detach((rt_object_t)thread);//将系统线程从object管理系统中移除
    }
    else//非系统线程(动态申请内存)直接插入到僵尸列表
    {
        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//非系统线程则丢到僵尸线程表中
    }

    /* switch to next task */
    rt_schedule();//呼叫线程调度

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}

线程分离/删除

线程分离和线程删除函数差别如下:
线程分离函数可以将静态线程从object中移除,线程删除函数则只能将动态分配的线程移除到僵尸线程表中

/**
 * This function will detach a thread. The thread object will be removed from
 * thread queue and detached/deleted from system object management.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_detach(rt_thread_t thread)
{
    rt_base_t lock;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);//线程对象
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread));//这个判断不对,RT_ASSERT宏默认关

    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
        return RT_EOK;

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);//从就绪表中移除
    }

    _thread_cleanup_execute(thread);//线程清理

    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));

    /* change stat */
    thread->stat = RT_THREAD_CLOSE;//改变线程状态

    if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)
    {
        rt_object_detach((rt_object_t)thread);//栈中分配的线程直接从object管理表中移除
    }
    else
    {
        /* disable interrupt */
        lock = rt_hw_interrupt_disable();
        /* insert to defunct thread list */
        rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));//动态分配的线程移除到僵尸列表中
        /* enable interrupt */
        rt_hw_interrupt_enable(lock);
    }

    return RT_EOK;
}

/**
 * This function will delete a thread. The thread object will be removed from
 * thread queue and deleted from system object management in the idle thread.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_delete(rt_thread_t thread)
{
    rt_base_t lock;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);
    RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE);

    if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
        return RT_EOK;

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT)
    {
        /* remove from schedule */
        rt_schedule_remove_thread(thread);
    }

    _thread_cleanup_execute(thread);

    /* release thread timer */
    rt_timer_detach(&(thread->thread_timer));

    /* disable interrupt */
    lock = rt_hw_interrupt_disable();

    /* change stat */
    thread->stat = RT_THREAD_CLOSE;

    /* insert to defunct thread list */
    rt_list_insert_after(&rt_thread_defunct, &(thread->tlist));

    /* enable interrupt */
    rt_hw_interrupt_enable(lock);

    return RT_EOK;
}
#endif

线程定时

/**
 * This function will let current thread sleep for some ticks.
 *
 * @param tick the sleep ticks
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
    /* set to current thread */
    thread = rt_current_thread;
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* suspend thread */
    rt_thread_suspend(thread);//挂起该线程

    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);//设置挂起时间
    rt_timer_start(&(thread->thread_timer));//开始计时

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    rt_schedule();//线程调度

    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;

    return RT_EOK;
}
/**
 * This function will suspend the specified thread.
 *
 * @param thread the thread to be suspended
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 *
 * @note if suspend self thread, after this function call, the
 * rt_schedule() must be invoked.
 */
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend:  %s\n", thread->name));

    if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
    {
        RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n",
                                       thread->stat));

        return -RT_ERROR;
    }

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* change thread stat */
    rt_schedule_remove_thread(thread);//将该线程从就绪表中移除
    thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK);//将状态设置为RT_THREAD_SUSPEND 

    /* stop thread timer anyway */
    rt_timer_stop(&(thread->thread_timer));//停止计时

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread));
    return RT_EOK;
}
/**
 * This function will control thread behaviors according to control command.
 *
 * @param thread the specified thread to be controlled
 * @param cmd the control command, which includes
 *  RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
 *  RT_THREAD_CTRL_STARTUP for starting a thread;
 *  RT_THREAD_CTRL_CLOSE for delete a thread;
 *  RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.
 * @param arg the argument of control command
 *
 * @return RT_EOK
 */
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg)
{
    register rt_base_t temp;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    switch (cmd)
    {
    case RT_THREAD_CTRL_CHANGE_PRIORITY: //改变线程优先级
        /* disable interrupt */
        temp = rt_hw_interrupt_disable();

        /* for ready thread, change queue */
        if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) //线程在就绪表中
        {
            /* remove thread from schedule queue first */
            rt_schedule_remove_thread(thread); //先将该线程移除

            /* change thread priority */
            thread->current_priority = *(rt_uint8_t *)arg; //修改线程优先级

            /* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
#else
            thread->number_mask = 1 << thread->current_priority;//设置优先级mask
#endif

            /* insert thread to schedule queue again */
            rt_schedule_insert_thread(thread);//修改好优先级后重新插入线程表
        }
        else //线程未在就绪表中
        {
            thread->current_priority = *(rt_uint8_t *)arg;

            /* recalculate priority attribute */
#if RT_THREAD_PRIORITY_MAX > 32
            thread->number      = thread->current_priority >> 3;            /* 5bit */
            thread->number_mask = 1 << thread->number;
            thread->high_mask   = 1 << (thread->current_priority & 0x07);   /* 3bit */
#else
            thread->number_mask = 1 << thread->current_priority;
#endif
        }

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
        break;

    case RT_THREAD_CTRL_STARTUP://启动线程
        return rt_thread_startup(thread);

    case RT_THREAD_CTRL_CLOSE://关闭线程/分离线程

        if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE)//静态线程使用detech
        {
            return rt_thread_detach(thread);
        }
#ifdef RT_USING_HEAP
        else //动态线程使用delete
        {
            return rt_thread_delete(thread);
        }
#endif

    default:
        break;
    }

    return RT_EOK;
}
/**
 * This function will lock the thread scheduler.
 */
//该函数会使rt_scheduler_lock_nest ++,从而锁住scheduler,确保在解锁之前当前代码段不会被scheduler中断执行
void rt_enter_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */
    rt_scheduler_lock_nest ++;

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}

/**
 * This function will unlock the thread scheduler.
 */
void rt_exit_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    rt_scheduler_lock_nest --;
    if (rt_scheduler_lock_nest <= 0)
    {
        rt_scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        if (rt_current_thread)
        {
            /* if scheduler is started, do a schedule */
            //这里因为如果线程systic timer超时了,本来需要做rt_schedule,但是因为rt_schedule被锁住,而没有做
            //所以会在解锁后做一次,如果该线程确实超时,那么就会执行shedule,线程时间片还没耗尽的话,因为它的优先级是排在
            //最前的,所以rt_schedule中会有判断当前from和to的线程是一致的,就不会切换。
            rt_schedule();
        }
    }
    else
    {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);
    }
}
/**
 * This function is the timeout function for thread, normally which is invoked
 * when thread is timeout to wait some resource.
 *
 * @param parameter the parameter of thread timeout function
 */
void rt_thread_timeout(void *parameter)
{
    struct rt_thread *thread;

    thread = (struct rt_thread *)parameter;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* set error number */
    thread->error = -RT_ETIMEOUT;

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));//do nothing

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);//将线程插入到就绪表

    /* do schedule */
    rt_schedule();
}

/**
 * This function will find the specified thread.
 *
 * @param name the name of thread finding
 *
 * @return the found thread
 *
 * @note please don't invoke this function in interrupt status.
 */
rt_thread_t rt_thread_find(char *name)
{
    return (rt_thread_t)rt_object_find(name, RT_Object_Class_Thread);
}

Rtthread thread 内部timer作用:

thread结构体中包含一个timer成员:

struct rt_timer thread_timer;                       /**< built-in thread timer */

在init_thread函数里面会对其进行初始化:

    /* initialize thread timer */
    rt_timer_init(&(thread->thread_timer),
                  thread->name,
                  rt_thread_timeout,
                  thread,
                  0,
                  RT_TIMER_FLAG_ONE_SHOT);

这里设置的超时回调函数为rt_thread_timeout,初始超时时间为0,RT_TIMER_FLAG_ONE_SHOT
为单次定时事件。
再看看rt_thread_timeout实现:
定时时间超时的时候会调用该函数,函数参数为该线程的信息。
主要做了如下操作:
1.设置thread->error 为 -RT_ETIMEOUT
2.移除当前线程节点
3.将该线程再次插入到就绪列表
4.执行线程调度

void rt_thread_timeout(void *parameter)
{
    struct rt_thread *thread;

    thread = (struct rt_thread *)parameter;

    /* thread check */
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* set error number */
    thread->error = -RT_ETIMEOUT;//

    /* remove from suspend list */
    rt_list_remove(&(thread->tlist));

    /* insert to schedule ready list */
    rt_schedule_insert_thread(thread);

    /* do schedule */
    rt_schedule();
}

那么什么时候会执行上述超时函数呢?
答案是在调用rt_thread_delay(rt_tick_t tick)的时候,rt_thread_delay会调用rt_thread_sleep
调用rt_thread_sleep的时候,函数执行下面的动作:
1.先调用rt_thread_suspend(thread)将当前线程休眠,移出就绪表。
2.调用rt_timer_control设置定时时间(休眠时间)。
3.调用rt_timer_start开启定时。
4.因为当前线程已经休眠,所以需要调用rt_schedule()调度到新的线程执行。
5.将thread->error = RT_EOK

rt_err_t rt_thread_delay(rt_tick_t tick)
{
    return rt_thread_sleep(tick);
}
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();
    /* set to current thread */
    thread = rt_current_thread;
    RT_ASSERT(thread != RT_NULL);
    RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread);

    /* suspend thread */
    rt_thread_suspend(thread);

    /* reset the timeout of thread timer and start it */
    rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
    rt_timer_start(&(thread->thread_timer));

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    rt_schedule();

    /* clear error number of this thread to RT_EOK */
    if (thread->error == -RT_ETIMEOUT)
        thread->error = RT_EOK;

    return RT_EOK;
}

这样当线程delay或者休眠时就会让出cpu,并在休眠时间到达目标值时通过rt_thread_timeout执行新的
调度。
rt_tick_increase函数会在systick中断中被调用,每次调用都会调用timer模块的rt_timer_check函数检查
是否有新的超时事件.
当线程被调用detech或者delete的时候,线程的detech/delete函数也会分别调用线程timer的detech/delete,
将该timer从object中移除。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tony++

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值