thread_create 和 thread_resume

在lk中我们一般通过thread_create 来新建一个thread,但这个thread 是THREAD_SUSPENDED,必须要调用thread_resume
才能开始运行
enum thread_state {
THREAD_SUSPENDED = 0,
THREAD_READY,
THREAD_RUNNING,
THREAD_BLOCKED,
THREAD_SLEEPING,
THREAD_DEATH,
};
thread_resume(thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
我们来看看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));
if (!t)
return NULL;


init_thread_struct(t, name);


t->entry = entry;
t->arg = arg;
t->priority = priority;
t->saved_critical_section_count = 1; /* we always start inside a critical section */
t->state = THREAD_SUSPENDED;
t->blocking_wait_queue = NULL;
t->wait_queue_block_ret = NO_ERROR;


/* create the stack */
t->stack = malloc(stack_size);
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);


/* add it to the global thread list */
enter_critical_section();
list_add_head(&thread_list, &t->thread_list_node);
exit_critical_section();


return t;
}
这个函数但大部分在做新thread_t结构体的初始化。在最后调用list_add_head将这个新建的thread加入到thread_list 中.
/* global thread list */
static struct list_node thread_list;
所有的thread 都是放在这个全局的thread_list 中
现在为止我们的thread 已经建好了,但是其状态是t->state = THREAD_SUSPENDED;我们需要调用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)
return ERR_NOT_SUSPENDED;


enter_critical_section();
t->state = THREAD_READY;
insert_in_run_queue_head(t);
thread_yield();
exit_critical_section();


return NO_ERROR;
}
这个函数会先判断t->state 是不是THREAD_READY 或者 THREAD_RUNNING,如果是的话就退出,说明出错了,由于我们是
新建一个thread,其状态是THREAD_SUSPENDED,所以继续往下走
将thread的状态设成THREAD_READY。
然后调用insert_in_run_queue_head 插入到将要运行thread的list中
/* run queue manipulation */
static void insert_in_run_queue_head(thread_t *t)
{
#if THREAD_CHECKS
ASSERT(t->magic == THREAD_MAGIC);
ASSERT(t->state == THREAD_READY);
ASSERT(!list_in_list(&t->queue_node));
ASSERT(in_critical_section());
#endif


list_add_head(&run_queue[t->priority], &t->queue_node);
run_queue_bitmap |= (1<<t->priority);
}
其中static struct list_node run_queue[NUM_PRIORITIES];  #define NUM_PRIORITIES 32
可以run_queue是一个数组,每个优先级对应数组中的一样。其中每一项又是一个list.
thread_resume 在把这个thread 放到run_queue后,继续调用thread_yield 来运行
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;
current_thread->remaining_quantum = 0;
insert_in_run_queue_tail(current_thread);
thread_resched();


exit_critical_section();
}
这个函数将当前正在运行的thread的状态设成THREAD_READY,然后调用insert_in_run_queue_tail将
当前thread 插入到run_queue 的最后面
然后调用thread_resched 来进程thread 切换
void thread_resched(void)
{
thread_t *oldthread;
thread_t *newthread;


oldthread = current_thread;


int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES);
//dprintf(SPEW, "bitmap 0x%x, next %d\n", run_queue_bitmap, next_queue);


newthread = list_remove_head_type(&run_queue[next_queue], thread_t, queue_node);


if (list_is_empty(&run_queue[next_queue]))
run_queue_bitmap &= ~(1<<next_queue);


newthread->state = THREAD_RUNNING;


if (newthread == oldthread)
return;


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




/* do the switch */
oldthread->saved_critical_section_count = critical_section_count;
current_thread = newthread;
critical_section_count = newthread->saved_critical_section_count;
arch_context_switch(oldthread, newthread);
}


通过list_remove_head_type 异常并返回在run_queue 头部的thread,由于这次切换的时候是找
优先级高的thread的运行,因此如果当前还有比我们优先级高的thread,可能这次运行的不是我们前面
新建的thread
int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES);
将这个thread的状态切换成newthread->state = THREAD_RUNNING
最后调用arch_context_switch 来进行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);
}
由于当前cpu是arm,因此调用arm_context_switch来切换
/* context switch frame is as follows:
* ulr
* usp
* lr
* r11
* r10
* r9
* r8
* r7
* r6
* r5
* r4
*/
/* arm_context_switch(addr_t *old_sp, addr_t new_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 */
mov r12, lr
stmia r3, { r4-r11, r12, r13, r14 }^

/* save old sp */
str r3, [r0] 


/* clear any exlusive locks that the old thread holds */
#if ARM_ISA_ARMV7
/* can clear it directly */
.word 0xf57ff01f // 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 }^
mov lr, r12 /* restore lr */
add sp, r1, #(11*4)     /* restore sp */
bx lr

其实现比较简单就是保存当前thread的寄存器,然后将新thread的寄存器从stack中load到寄存器中,并执行bx lr 跳到新thread来运行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值