lk中的event wait

lk中提供event来协调thread之间的工作,如fastboot中的thread会一直等待usb 给发送event事件后才继续往下走。
例如fastboot_init 中会调用event_init来初始化两个event。
int fastboot_init(void *base, unsigned size)
{
thread_t *thr;
dprintf(INFO, "fastboot_init()\n");


download_base = base;
download_max = size;


event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);


}


我们来看看event_init具体做了什么事情
void event_init(event_t *e, bool initial, uint flags)
{
e->magic = EVENT_MAGIC;
e->signalled = initial;
e->flags = flags;
wait_queue_init(&e->wait);
}


原来就是就是给event_t这个结构体赋值,然后调用wait_queue_init来初始化一个list。
void wait_queue_init(wait_queue_t *wait)
{
wait->magic = WAIT_QUEUE_MAGIC;
list_initialize(&wait->list);
wait->count = 0;
}
下来看看具体要怎么使用event
首先在fastboot_hanlder 中会等待usb_online这个event事件
static int fastboot_handler(void *arg)
{
for (;;) {
event_wait(&usb_online);
fastboot_command_loop();
}
return 0;
}


由此我们知道使用event的两方,肯定一个在wait这个event,一个在signal 这个event
我们先看看event_wait是如何wait event的
status_t event_wait(event_t *e)
{
return event_wait_timeout(e, INFINITE_TIME);
}


继续调用event_wait_timeout,原来event还可以是以一个timeout参数,这个参数默认是无限等待
继续看event_wait_timeout


status_t event_wait_timeout(event_t *e, time_t timeout)
{
status_t ret = NO_ERROR;


enter_critical_section();


if (e->signalled) {
/* signalled, we're going to fall through */
if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) {
/* autounsignal flag lets one thread fall through before unsignalling */
e->signalled = false;
}
} else {
/* unsignalled, block here */
ret = wait_queue_block(&e->wait, timeout);
if (ret < 0)
goto err;
}


err:
exit_critical_section();


return ret;
}


这个函数首先看是否我们在调用event_wait的时候,是否已经有人signal这个event了,如果已经signal了,就没必须等待了,直接返回就可以了


否则就调用wait_queue_block
status_t wait_queue_block(wait_queue_t *wait, time_t timeout)
{
timer_t timer;


if (timeout == 0)
return ERR_TIMED_OUT;


list_add_tail(&wait->list, &current_thread->queue_node);
wait->count++;
current_thread->state = THREAD_BLOCKED;
current_thread->blocking_wait_queue = wait;
current_thread->wait_queue_block_ret = NO_ERROR;


/* if the timeout is nonzero or noninfinite, set a callback to yank us out of the queue */
if (timeout != INFINITE_TIME) {
timer_initialize(&timer);
timer_set_oneshot(&timer, timeout, wait_queue_timeout_handler, (void *)current_thread);
}


thread_block();


/* we don't really know if the timer fired or not, so it's better safe to try to cancel it */
if (timeout != INFINITE_TIME) {
timer_cancel(&timer);
}


return current_thread->wait_queue_block_ret;
}


wait_queue_block 首先检查设定的timeout 参数是否为0,如果为0,直接退出,否则将current_thread加到wait list中,并将当前thread的state设为THREAD_BLOCKED;
后面继续检查timeout的参数是否是无限等待,如果不是则通过
timer_initialize(&timer);
timer_set_oneshot(&timer, timeout, wait_queue_timeout_handler, (void *)current_thread);
建立一个timer,在timer的callback函数中,检查是否针对这个event的singal事件发送


timer的callback 如下:
static enum handler_return wait_queue_timeout_handler(timer_t *timer, time_t now, void *arg)
{
thread_t *thread = (thread_t *)arg;


#if THREAD_CHECKS
ASSERT(thread->magic == THREAD_MAGIC);
#endif


if (thread_unblock_from_wait_queue(thread, false, ERR_TIMED_OUT) >= NO_ERROR)
return INT_RESCHEDULE;


return INT_NO_RESCHEDULE;
}


继续调用thread_unblock_from_wait_queue


status_t thread_unblock_from_wait_queue(thread_t *t, bool reschedule, status_t wait_queue_error)
{
enter_critical_section();
list_delete(&t->queue_node);
t->blocking_wait_queue->count--;
t->blocking_wait_queue = NULL;
t->state = THREAD_READY;
t->wait_queue_block_ret = wait_queue_error;
insert_in_run_queue_head(t);


if (reschedule)
thread_resched();


exit_critical_section();


return NO_ERROR;
}


thread_unblock_from_wait_queue 会将当前到期的thread从wait list中删除,将thread的状态设定为THREAD_READY;并加到到run_queue的前面,这样下一次调度是就有可能运行这个thread


event的wait就讲完了。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值