1// Copyright 2016 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include <object/wait_state_observer.h>
8
9#include <assert.h>
10
11#include <kernel/event.h>
12
13#include <object/handle.h>
14#include <object/dispatcher.h>
15
16#include <fbl/type_support.h>
17
18WaitStateObserver::~WaitStateObserver() {
19    DEBUG_ASSERT(!dispatcher_);
20}
21
22zx_status_t WaitStateObserver::Begin(Event* event,
23                                     Handle* handle,
24                                     zx_signals_t watched_signals) {
25    canary_.Assert();
26    DEBUG_ASSERT(!dispatcher_);
27
28    event_ = event;
29    handle_ = handle;
30    watched_signals_ = watched_signals;
31    dispatcher_ = handle->dispatcher();
32    wakeup_reasons_ = 0u;
33
34    auto status = dispatcher_->add_observer(this);
35    if (status != ZX_OK) {
36        dispatcher_.reset();
37        return status;
38    }
39    return ZX_OK;
40}
41
42zx_signals_t WaitStateObserver::End() {
43    canary_.Assert();
44    DEBUG_ASSERT(dispatcher_);
45    DEBUG_ASSERT(dispatcher_->has_state_tracker());
46
47    dispatcher_->RemoveObserver(this);
48    dispatcher_.reset();
49
50    // Return the set of reasons that we may have been woken.  Basically, this
51    // is set of satisfied bits which were ever set while we were waiting on the list.
52    return wakeup_reasons_;
53}
54
55StateObserver::Flags WaitStateObserver::OnInitialize(zx_signals_t initial_state,
56                                                     const StateObserver::CountInfo* cinfo) {
57    canary_.Assert();
58
59    // Record the initial state of the state tracker as our wakeup reason.  If
60    // we are going to become immediately signaled, the reason is contained
61    // somewhere in this initial state.
62    wakeup_reasons_ = initial_state;
63
64    if (initial_state & watched_signals_) {
65        event_->Signal();
66    }
67
68    return 0;
69}
70
71StateObserver::Flags WaitStateObserver::OnStateChange(zx_signals_t new_state) {
72    canary_.Assert();
73
74    // If we are still on our StateTracker's list of observers, and the
75    // StateTracker's state has changed, accumulate the reasons that we may have
76    // woken up.  In particular any satisfied bits which have become set
77    // while we were on the list may have been reasons to wake up.
78    wakeup_reasons_ |= new_state;
79
80    if (new_state & watched_signals_) {
81        event_->Signal();
82    }
83
84    return 0;
85}
86
87StateObserver::Flags WaitStateObserver::OnCancel(const Handle* handle) {
88    canary_.Assert();
89
90    if (handle == handle_) {
91        wakeup_reasons_ |= ZX_SIGNAL_HANDLE_CLOSED;
92        event_->Signal(ZX_ERR_CANCELED);
93        return kHandled;
94    } else {
95        return 0;
96    }
97}
98