Repository navigation
Expand file tree
/
Copy pathevent.cpp
More file actions
163 lines (141 loc) · 5.03 KB
/
Copy pathevent.cpp
File metadata and controls
163 lines (141 loc) · 5.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
#include "vortex2_internal.h"
namespace vx {
Event::Event(Device* dev) : device_(dev) {}
Event::~Event() {}
vx_result_t Event::create(Device* dev, Event** out) {
if (!dev || !out) return VX_ERR_INVALID_VALUE;
*out = new Event(dev);
return VX_SUCCESS;
}
void Event::signal(uint64_t value) {
{
std::lock_guard<std::mutex> g(mu_);
if (value <= counter_) return; // monotonic — no decrement, no-op
counter_ = value;
}
cv_.notify_all();
}
void Event::complete(vx_result_t status) {
{
std::lock_guard<std::mutex> g(mu_);
if (status != VX_SUCCESS && error_ == VX_SUCCESS) {
error_ = status;
}
if (counter_ >= 1) {
// Already signaled — but if a later error came in, broadcast so
// any waiters that woke on counter==1 with error==SUCCESS can
// re-observe the error. In practice complete() is called once
// per command so this is a defensive path.
if (status != VX_SUCCESS) cv_.notify_all();
return;
}
counter_ = 1;
}
cv_.notify_all();
}
vx_result_t Event::wait_value(uint64_t value, uint64_t timeout_ns) {
std::unique_lock<std::mutex> g(mu_);
const auto pred = [&] {
return counter_ >= value || error_ != VX_SUCCESS;
};
if (!pred()) {
if (timeout_ns == VX_TIMEOUT_INFINITE) {
cv_.wait(g, pred);
} else {
if (!cv_.wait_for(g, std::chrono::nanoseconds(timeout_ns), pred))
return VX_ERR_TIMEOUT;
}
}
return (error_ != VX_SUCCESS) ? error_ : VX_SUCCESS;
}
uint64_t Event::get_value() const {
std::lock_guard<std::mutex> g(mu_);
return counter_;
}
void Event::set_profile(uint64_t queued_ns, uint64_t submit_ns,
uint64_t start_ns, uint64_t end_ns) {
std::lock_guard<std::mutex> g(mu_);
profile_.queued_ns = queued_ns;
profile_.submit_ns = submit_ns;
profile_.start_ns = start_ns;
profile_.end_ns = end_ns;
has_profile_ = true;
}
vx_result_t Event::get_profile(vx_profile_info_t* out) {
if (!out) return VX_ERR_INVALID_VALUE;
std::lock_guard<std::mutex> g(mu_);
if (!has_profile_) return VX_ERR_NOT_SUPPORTED;
*out = profile_;
return VX_SUCCESS;
}
} // namespace vx
// ============================================================================
// C entry points — timeline API
// ============================================================================
using namespace vx;
extern "C" vx_result_t vx_event_create(vx_device_h dev, vx_event_h* out) {
VX_C_ENTRY_TRY
if (!dev || !out) return VX_ERR_INVALID_VALUE;
Event* ev = nullptr;
auto r = Event::create(to_device(dev), &ev);
if (r != VX_SUCCESS) return r;
*out = to_handle(ev);
return VX_SUCCESS;
VX_C_ENTRY_CATCH
}
extern "C" vx_result_t vx_event_signal(vx_event_h ev, uint64_t value) {
if (!ev) return VX_ERR_INVALID_HANDLE;
to_event(ev)->signal(value);
return VX_SUCCESS;
}
extern "C" vx_result_t vx_event_get_value(vx_event_h ev, uint64_t* out_value) {
if (!ev) return VX_ERR_INVALID_HANDLE;
if (!out_value) return VX_ERR_INVALID_VALUE;
*out_value = to_event(ev)->get_value();
return VX_SUCCESS;
}
extern "C" vx_result_t vx_event_wait_value(vx_event_h ev, uint64_t value,
uint64_t timeout_ns) {
VX_C_ENTRY_TRY
if (!ev) return VX_ERR_INVALID_HANDLE;
return to_event(ev)->wait_value(value, timeout_ns);
VX_C_ENTRY_CATCH
}
extern "C" vx_result_t vx_event_wait_values(uint32_t n,
const vx_event_h* evs,
const uint64_t* values,
uint64_t timeout_ns) {
VX_C_ENTRY_TRY
if (n != 0 && (!evs || !values)) return VX_ERR_INVALID_VALUE;
// Single-event fast path is the common case; multi-event loops are fine
// for small n (OpenCL clients always pass <= 16).
for (uint32_t i = 0; i < n; ++i) {
if (!evs[i]) return VX_ERR_INVALID_HANDLE;
auto r = to_event(evs[i])->wait_value(values[i], timeout_ns);
if (r != VX_SUCCESS) return r;
}
return VX_SUCCESS;
VX_C_ENTRY_CATCH
}
extern "C" vx_result_t vx_event_retain(vx_event_h ev) {
if (!ev) return VX_ERR_INVALID_HANDLE;
to_event(ev)->retain();
return VX_SUCCESS;
}
extern "C" vx_result_t vx_event_release(vx_event_h ev) {
if (!ev) return VX_ERR_INVALID_HANDLE;
to_event(ev)->release();
return VX_SUCCESS;
}
extern "C" vx_result_t vx_event_get_profiling(vx_event_h ev,
vx_profile_info_t* out) {
if (!ev) return VX_ERR_INVALID_HANDLE;
if (!out) return VX_ERR_INVALID_VALUE;
return to_event(ev)->get_profile(out);
}