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, ¤t_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就讲完了。