The event mechanism zircon

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/tiantao2012/article/details/94544279
在zircon中线程同步的机制之一就是event机制。
event机制的主要函数是event_signal 和 event_wait_deadline,其他的一些API 都是这两者的变种
我们先来看看
zx_status_t event_wait_deadline(event_t* e, zx_time_t deadline, bool interruptable) {
    return event_wait_worker(e, Deadline::no_slack(deadline), interruptable, 0);
}
这里直接调用event_wait_worker
static zx_status_t event_wait_worker(event_t* e,
                                     const Deadline& deadline,
                                     bool interruptable,
                                     uint signal_mask) {
    thread_t* current_thread = get_current_thread();
    zx_status_t ret = ZX_OK;

    DEBUG_ASSERT(e->magic == EVENT_MAGIC);
    DEBUG_ASSERT(!arch_blocking_disallowed());

    Guard<spin_lock_t, IrqSave> guard{ThreadLock::Get()};

    current_thread->interruptable = interruptable;
#如果在调用event_wait_deadline之前已经调用event_signal了,就走if的分支
    if (e->signaled) {
        /* signaled, we're going to fall through */
        if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) {
            /* autounsignal flag lets one thread fall through before unsignaling */
            e->signaled = false;
        }
    } else {
#正常情况下应该走这个case
        /* unsignaled, block here */
        ret = wait_queue_block_etc(&e->wait, deadline, signal_mask, ResourceOwnership::Normal);
    }

    current_thread->interruptable = false;

    return ret;
}
继续看下wait_queue_block_etc
zx_status_t wait_queue_block_etc(wait_queue_t* wait,
                                 const Deadline& deadline,
                                 uint signal_mask,
                                 ResourceOwnership reason) TA_REQ(thread_lock) {
    thread_t* current_thread = get_current_thread();

    DEBUG_ASSERT_MAGIC_CHECK(wait);
    DEBUG_ASSERT(current_thread->state == THREAD_RUNNING);
    DEBUG_ASSERT(arch_ints_disabled());
    DEBUG_ASSERT(spin_lock_held(&thread_lock));

    if (WAIT_QUEUE_VALIDATION) {
        wait_queue_validate_queue(wait);
    }
#把当前线程插入到等待队列wait中
    zx_status_t res = internal::wait_queue_block_etc_pre(wait, deadline, signal_mask, reason);
    if (res != ZX_OK) {
        return res;
    }
#设置一个timer,超过时间自动将等待的thread唤醒
    return internal::wait_queue_block_etc_post(wait, deadline);
}
inline zx_status_t wait_queue_block_etc_post(wait_queue_t* wait,
                                             const Deadline& deadline) TA_REQ(thread_lock) {
    thread_t* current_thread = get_current_thread();
    timer_t timer;
#如果等待的时间不是无限长,则设置一个timer
    // if the deadline is nonzero or noninfinite, set a callback to yank us out of the queue
    if (deadline.when() != ZX_TIME_INFINITE) {
        timer_init(&timer);
        timer_set(&timer, deadline, wait_queue_timeout_handler, (void*)current_thread);
    }

    ktrace_ptr(TAG_KWAIT_BLOCK, wait, 0, 0);
#让出当前cpu
    sched_block();
#当当前thread被接收到event_signal后会从这里开始执行
    ktrace_ptr(TAG_KWAIT_UNBLOCK, wait, current_thread->blocked_status, 0);
#已经被唤醒,则取消超时的timer
    // we don't really know if the timer fired or not, so it's better safe to try to cancel it
    if (deadline.when() != ZX_TIME_INFINITE) {
        timer_cancel(&timer);
    }

    return current_thread->blocked_status;
}
event_signal的实现
int event_signal(event_t* e, bool reschedule) {
#加锁保护,这种锁当函数返回的时候自动销毁
    Guard<spin_lock_t, IrqSave> guard{ThreadLock::Get()};
    return event_signal_internal(e, reschedule, ZX_OK);
}
event 在signal 之后可以自动unsign 或者主动调用函数event_unsigned
static int event_signal_internal(event_t* e, bool reschedule,
                                 zx_status_t wait_result) TA_REQ(thread_lock) {
    DEBUG_ASSERT(e->magic == EVENT_MAGIC);

    int wake_count = 0;

    if (!e->signaled) {
        if (e->flags & EVENT_FLAG_AUTOUNSIGNAL) {
            /* try to release one thread and leave unsignaled if successful */
我们以自动unsign为例
            if ((wake_count = wait_queue_wake_one(&e->wait, reschedule, wait_result)) <= 0) {
                /*
                 * if we didn't actually find a thread to wake up, go to
                 * signaled state and let the next call to event_wait
                 * unsignal the event.
                 */
#表示这个event 已经被signed过了
                e->signaled = true;
            }
#需要主动调用函数event_unsigned
        } else {
            /* release all threads and remain signaled */
            e->signaled = true;
            wake_count = wait_queue_wake_all(&e->wait, reschedule, wait_result);
        }
    }

    return wake_count;
}
int wait_queue_wake_all(wait_queue_t* wait, bool reschedule, zx_status_t wait_queue_error) {
    thread_t* t;
    int ret = 0;

    
    struct list_node list = LIST_INITIAL_VALUE(list);

   
#从的等待wait中找到正在等待的thread,可能有多个thread在等待
    while ((t = wait_queue_peek(wait))) {
        internal::wait_queue_dequeue_thread_internal(wait, t, wait_queue_error);
        list_add_tail(&list, &t->queue_node);
        ret++;
    }

    DEBUG_ASSERT(ret > 0);
    DEBUG_ASSERT(wait->count == 0);

    ktrace_ptr(TAG_KWAIT_WAKE, wait, 0, 0);

   
#唤醒所有的threads,把这些thread放到一个cpu的run queue中,然后根据本地cpu的run queue是否改变来决定是否重新调度
    bool local_resched = sched_unblock_list(&list);
    if (reschedule && local_resched) {
        sched_reschedule();
    }

    return ret;
}

 

Guess you like

Origin blog.csdn.net/tiantao2012/article/details/94544279