1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <trace/observer.h>
6
7#include <zircon/assert.h>
8
9namespace trace {
10
11TraceObserver::TraceObserver() {
12}
13
14TraceObserver::~TraceObserver() {
15    Stop();
16}
17
18void TraceObserver::Start(async_dispatcher_t* dispatcher, fbl::Closure callback) {
19    ZX_DEBUG_ASSERT(dispatcher);
20    ZX_DEBUG_ASSERT(callback);
21
22    Stop();
23    callback_ = fbl::move(callback);
24
25    zx_status_t status = zx::event::create(0u, &event_);
26    ZX_ASSERT(status == ZX_OK);
27    trace_register_observer(event_.get());
28
29    wait_.set_object(event_.get());
30    wait_.set_trigger(ZX_EVENT_SIGNALED);
31    BeginWait(dispatcher);
32}
33
34void TraceObserver::Stop() {
35    wait_.Cancel();
36    callback_ = nullptr;
37
38    if (event_) {
39        trace_unregister_observer(event_.get());
40        event_.reset();
41    }
42}
43
44void TraceObserver::Handle(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
45                           const zx_packet_signal_t* signal) {
46    if (status != ZX_OK) {
47        Stop();
48        return;
49    }
50
51    ZX_DEBUG_ASSERT(status == ZX_OK);
52    ZX_DEBUG_ASSERT(signal->observed & ZX_EVENT_SIGNALED);
53
54    // Clear the signal otherwise we'll keep getting called.
55    // Clear the signal *before* invoking the callback because there's no
56    // synchronization between the engine and the observers, thus it's possible
57    // that an observer could get back to back notifications.
58    event_.signal(ZX_EVENT_SIGNALED, 0u);
59
60    // Invoke the callback.
61    callback_();
62
63    // Tell engine we're done.
64    trace_notify_observer_updated(event_.get());
65
66    // Wait again!
67    BeginWait(dispatcher);
68}
69
70void TraceObserver::BeginWait(async_dispatcher_t* dispatcher) {
71    zx_status_t status = wait_.Begin(dispatcher);
72    if (status != ZX_OK)
73        Stop();
74}
75
76} // namespace trace
77