MTK lk源码解析3( lk 阶段thread.c解析)

http://blog.csdn.net/xichangbao/article/details/51484585

从thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));展开对lk中thread的分析。

  1. struct thread。
typedef struct thread {
    int magic; // thread魔数'thrd'
    struct list_node thread_list_node; // thread链表,用于将lk中的thread链接起来

    /* active bits */
    struct list_node queue_node; // 运行队列链表
    int priority; // thread优先级
    enum thread_state state; // thread状态,分为THREAD_SUSPENDED,THREAD_READY, THREAD_RUNNING,  THREAD_BLOCKED,  THREAD_SLEEPING,  THREAD_DEATH等六种状态
    int saved_critical_section_count; // 相当于一个简单的锁机制
    int remaining_quantum; // 

    /* if blocked, a pointer to the wait queue */
    struct wait_queue *blocking_wait_queue; // 等待队列
    status_t wait_queue_block_ret; // 等待队列唤醒时的状态

    /* architecture stuff */
    struct arch_thread arch; // 比较重要,目前只保留的thread的sp(堆栈)指针

    /* stack stuff */
    void *stack; // 初始化时分配的堆栈空间指针
    size_t stack_size; // 初始化时分配的堆栈空间大小

    /* entry point */
    thread_start_routine entry; // thread入口函数
    void *arg; // thread入口函数的参数

    /* return code */
    int retcode; // thread退出时的返回值

    /* thread local storage */
    uint32_t tls[MAX_TLS_ENTRY]; // 线程本地存储,未实现

    char name[32]; // 线程名称
} thread_t;

  1. thread_create()。
thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size)
{
    thread_t *t;

    t = malloc(sizeof(thread_t)); // 从lk的heap中分配thread结构体内存,lk的heap实现比较简单,但功能齐全,有时间可以看一下
    if (!t)
        return NULL;

    init_thread_struct(t, name); // 初始化thread,做了三个动作,结构体清零,设置魔数,设置name

    t->entry = entry; // 对thread入口函数指针进行赋值
    t->arg = arg;  // 对thread入口函数参数进行赋值
    t->priority = priority; // 设置thread优先级
    t->saved_critical_section_count = 1; /* we always start inside a critical section */
    t->state = THREAD_SUSPENDED; // 设置thread的当前状态为挂起
    t->blocking_wait_queue = NULL; // 等待队列为空
    t->wait_queue_block_ret = NO_ERROR;

    /* create the stack */
    t->stack = malloc(stack_size); // 为thread分配堆栈
    if (!t->stack) {
        free(t);
        return NULL;
    }

    t->stack_size = stack_size; // 记录堆栈大小

    /* inheirit thread local storage from the parent */
    int i;
    for (i=0; i < MAX_TLS_ENTRY; i++)
        t->tls[i] = current_thread->tls[i]; // 未实现

    /* set up the initial stack frame */
    arch_thread_initialize(t); // 设置栈帧等,这个函数十分关键,因为涉及到了thread的切换

    /* add it to the global thread list */
    enter_critical_section();
    list_add_head(&thread_list, &t->thread_list_node); // 将新生成的thread加入到lk的thread链表中
    exit_critical_section();

    return t;
}

struct context_switch_frame {
    vaddr_t r4;
    vaddr_t r5;
    vaddr_t r6;
    vaddr_t r7;
    vaddr_t r8;
    vaddr_t r9;
    vaddr_t r10;
    vaddr_t r11;
    vaddr_t lr;
    vaddr_t usp;
    vaddr_t ulr;
};
注释刚刚到这里
void arch_thread_initialize(thread_t *t)
{
    // create a default stack frame on the stack
    vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size; // 计算栈顶地址

    // make sure the top of the stack is 8 byte aligned for EABI compliance
    stack_top = ROUNDDOWN(stack_top, 8); // 向下8byte对齐

    struct context_switch_frame *frame = (struct context_switch_frame *)(stack_top);
    frame--; // 这两行代码实现了的在栈顶预留了一个 context_switch_frame结构体的内存

    // fill it in
    memset(frame, 0, sizeof(*frame)); // 对 context_switch_frame结构体清零
    frame->lr = (vaddr_t)&initial_thread_func; // 栈帧的lr指针指向 initial_thread_func函数的地址

    // set the stack pointer
    t->arch.sp = (vaddr_t)frame; // 由于我们已经是使用了堆栈中的一部分(context_switch_frame 结构体使用的和向下对齐造成的),所以需要更新堆栈指针
}

static void initial_thread_func(void)
{
    int ret;

//    dprintf("initial_thread_func: thread %p calling %p with arg %p\n", current_thread, current_thread->entry, current_thread->arg);
//    dump_thread(current_thread);

    /* exit the implicit critical section we're within */
    exit_critical_section();

    ret = current_thread->entry(current_thread->arg); // 调用当前thread的entry函数,对bootstrap2来说就bootstrap2()函数

//    dprintf("initial_thread_func: thread %p exiting with %d\n", current_thread, ret);

    thread_exit(ret); // thread退出时做一些处理
}

void thread_exit(int retcode)
{
#if THREAD_CHECKS
    ASSERT(current_thread->magic == THREAD_MAGIC);
    ASSERT(current_thread->state == THREAD_RUNNING);
#endif

//    dprintf("thread_exit: current %p\n", current_thread);

    enter_critical_section();

    /* enter the dead state */
    current_thread->state = THREAD_DEATH; // 设置thread状态为死亡
    current_thread->retcode = retcode; // 设置thread的退出值

    /* schedule a dpc to clean ourselves up */
    dpc_queue(thread_cleanup_dpc, (void *)current_thread, DPC_FLAG_NORESCHED); // 对当前thread进行清理动作

    /* reschedule */
    thread_resched(); // thread调度,从lk thread链表中选一个thread继续运行

    panic("somehow fell through thread_exit()\n"); // 正常情况代码永远不会执行到这里。
    for(;;);
}

static void thread_cleanup_dpc(void *thread)
{
    thread_t *t = (thread_t *)thread;

//    dprintf(SPEW, "thread_cleanup_dpc: thread %p (%s)\n", t, t->name);

#if THREAD_CHECKS
    ASSERT(t->state == THREAD_DEATH);
    ASSERT(t->blocking_wait_queue == NULL);
    ASSERT(!list_in_list(&t->queue_node));
#endif

    /* remove it from the master thread list */
    enter_critical_section();
    list_delete(&t->thread_list_node); //  从lk thread链表中删除对应的thread
    exit_critical_section();

    /* free its stack and the thread structure itself */
    if (t->stack)
        free(t->stack); //  释放堆栈内存资源。

    free(t); // 释放thread结构体自身占用的内存资源
}


  1. thread_resume()。
status_t thread_resume(thread_t *t)
{
#if THREAD_CHECKS
    ASSERT(t->magic == THREAD_MAGIC);
    ASSERT(t->state != THREAD_DEATH);
#endif

    if (t->state == THREAD_READY || t->state == THREAD_RUNNING) //  仅当thread为挂起状态才会进行唤醒
        return ERR_NOT_SUSPENDED;

    enter_critical_section();
    t->state = THREAD_READY; // 设置thread状态为就绪
    insert_in_run_queue_head(t); // 将thread插入运行队列的头部
    thread_yield(); // 让渡处cpu资源,执行新的thread
    exit_critical_section();

    return NO_ERROR;
}

void thread_yield(void)
{
#if THREAD_CHECKS
    ASSERT(current_thread->magic == THREAD_MAGIC);
    ASSERT(current_thread->state == THREAD_RUNNING);
#endif

    enter_critical_section();

#if THREAD_STATS
    thread_stats.yields++;
#endif

    /* we are yielding the cpu, so stick ourselves into the tail of the run queue and reschedule */
    current_thread->state = THREAD_READY; // 将当前thread状态设置为就绪
    current_thread->remaining_quantum = 0; // 
    insert_in_run_queue_tail(current_thread); // 插入到运行队列尾部
    thread_resched(); // 执行thread调度

    exit_critical_section();
}

void thread_resched(void)
{
    thread_t *oldthread;
    thread_t *newthread;

//    dprintf("thread_resched: current %p: ", current_thread);
//    dump_thread(current_thread);

#if THREAD_CHECKS
    ASSERT(in_critical_section());
#endif

#if THREAD_STATS
    thread_stats.reschedules++;
#endif

    oldthread = current_thread; // 保存当前的thread的指针

    // at the moment, can't deal with more than 32 priority levels
    ASSERT(NUM_PRIORITIES <= 32);

    // should at least find the idle thread
#if THREAD_CHECKS
    ASSERT(run_queue_bitmap != 0);
#endif
 
    int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES); // 根据优先级选取运行队列
    //dprintf(ALWAYS, "bitmap 0x%x, next %d\n", run_queue_bitmap, next_queue);

    newthread = list_remove_head_type(&run_queue[next_queue], thread_t, queue_node); // 从运行队列头部选取一个新的thread

#if THREAD_CHECKS
    ASSERT(newthread);
#endif

    if (list_is_empty(&run_queue[next_queue]))
        run_queue_bitmap &= ~(1<<next_queue); // 当选取的运行队列中thread 链表为空时,清除对应优先级的 run_queue_bitmap位

#if 0
    // XXX make this more efficient
    newthread = NULL;
    for (i=HIGHEST_PRIORITY; i >= LOWEST_PRIORITY; i--) {
        newthread = list_remove_head_type(&run_queue[i], thread_t, queue_node);
        if (newthread)
            break;
    }
#endif

    //dprintf(ALWAYS, "newthread: ");
    //dump_thread(newthread);

    newthread->state = THREAD_RUNNING; // 设置新thread状态为正在运行

    if (newthread == oldthread)
        return; // 新旧thread相等时,说明没有别的thread了,直接退出thread调度,继续执行

    /* set up quantum for the new thread if it was consumed */
    if (newthread->remaining_quantum <= 0) {
        newthread->remaining_quantum = 5; // XXX make this smarter // 
    }

#if THREAD_STATS
    thread_stats.context_switches++;

    if (oldthread == idle_thread) {
        bigtime_t now = current_time_hires();
        thread_stats.idle_time += now - thread_stats.last_idle_timestamp;
    }
    if (newthread == idle_thread) {
        thread_stats.last_idle_timestamp = current_time_hires();
    }
#endif

#if THREAD_CHECKS
    ASSERT(critical_section_count > 0);
    ASSERT(newthread->saved_critical_section_count > 0);
#endif

#if PLATFORM_HAS_DYNAMIC_TIMER
    /* if we're switching from idle to a real thread, set up a periodic
     * timer to run our preemption tick.
     */
    if (oldthread == idle_thread) {
        timer_set_periodic(&preempt_timer, 10, (timer_callback)thread_timer_tick, NULL);
    } else if (newthread == idle_thread) {
        timer_cancel(&preempt_timer);
    }
#endif

    /* do the switch */
    oldthread->saved_critical_section_count = critical_section_count;
    current_thread = newthread; // 将新thread设置当前thread
    critical_section_count = newthread->saved_critical_section_count;
    arch_context_switch(oldthread, newthread); // 完成thread上下文切换,最终执行新thread的入口函数
}

void arch_context_switch(thread_t *oldthread, thread_t *newthread)
{
//    dprintf("arch_context_switch: old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
    arm_context_switch(&oldthread->arch.sp, newthread->arch.sp); // 调用汇编代码,r0为旧thread的 arch.sp 的地址 ,r1为新thread的 arch.sp
}

// 这一块对我来说还是只能理解大概,不能透彻的理解的
FUNCTION(arm_context_switch)
    /* save all the usual registers + user regs */
    /* the spsr is saved and restored in the iframe by exceptions.S */
    sub        r3, sp, #(11*4)        /* can't use sp in user mode stm */ // 这里的sp是r3保存的是sp-11*4的内存地址,即预留了可以保存11个32位寄存器内存空间
    mov        r12, lr // 将内核lr寄存器值保存到r12寄存器中
    stmia    r3, { r4-r11, r12, r13, r14 }^ // 保存r4-r11, r12, r13, r14等11个寄存器值(其中r13和r14为用户模式的)到r3指向的内存地址 中去

    /* save old sp */
    str        r3, [r0] // 将r3的值(保存了11个寄存器后的堆栈指针)保存到旧thread的的 arch.sp

    /* clear any exlusive locks that the old thread holds */
#if ARM_ISA_ARMV7
    clrex
#elif ARM_ISA_ARMV6
    /* have to do a fake strex to clear it */
    ldr        r0, =strex_spot
    strex    r3, r2, [r0]
#endif

    /* load new regs */
    ldmia    r1, { r4-r11, r12, r13, r14 }^ // 从新thread的堆栈中加载 r4-r11, r12, r13, r14等11个寄存器的值
    mov        lr, r12                /* restore lr */ // 从r12中恢复lr的值
    add        sp, r1, #(11*4)     /* restore sp */ // 恢复sp的值
    bx        lr // 跳到lr处继续执行,由前面的分析可知是跳转到 initial_thread_func函数继续执行


总结一下,thread切换的过程,先切换 current_thread的指针内容,使其指向新的thread,进行thread切换时,保存旧threa d的context_switch_frame的地址到旧threa d的arch.sp中,同时从新thread的arch.sp读取 context_switch_frame中的信息到相应寄存器中,然后跳转的新thread的lr指向的代码地址继续运行,如果新thread是第一次运行那么它的lr应该指向 initial_thread_func ,最后在 initial_thread_func函数执行 current_thread->entry(current_thread->arg)执行新thread的入口函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值