1 //
2 // Copyright 2012 Francisco Jerez
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 // OTHER DEALINGS IN THE SOFTWARE.
21 //
22
23 #include "api/util.hpp"
24 #include "core/event.hpp"
25
26 using namespace clover;
27
28 CLOVER_API cl_event
clCreateUserEvent(cl_context d_ctx,cl_int * r_errcode)29 clCreateUserEvent(cl_context d_ctx, cl_int *r_errcode) try {
30 auto &ctx = obj(d_ctx);
31
32 ret_error(r_errcode, CL_SUCCESS);
33 return desc(new soft_event(ctx, {}, false));
34
35 } catch (error &e) {
36 ret_error(r_errcode, e);
37 return NULL;
38 }
39
40 CLOVER_API cl_int
clSetUserEventStatus(cl_event d_ev,cl_int status)41 clSetUserEventStatus(cl_event d_ev, cl_int status) try {
42 auto &sev = obj<soft_event>(d_ev);
43
44 if (status > 0)
45 return CL_INVALID_VALUE;
46
47 if (sev.status() <= 0)
48 return CL_INVALID_OPERATION;
49
50 if (status)
51 sev.abort(status);
52 else
53 sev.trigger();
54
55 return CL_SUCCESS;
56
57 } catch (error &e) {
58 return e.get();
59 }
60
61 CLOVER_API cl_int
clWaitForEvents(cl_uint num_evs,const cl_event * d_evs)62 clWaitForEvents(cl_uint num_evs, const cl_event *d_evs) try {
63 auto evs = objs(d_evs, num_evs);
64
65 for (auto &ev : evs) {
66 if (ev.context() != evs.front().context())
67 throw error(CL_INVALID_CONTEXT);
68
69 if (ev.status() < 0)
70 throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
71 }
72
73 // Create a temporary soft event that depends on all the events in
74 // the wait list
75 auto sev = create<soft_event>(evs.front().context(), evs, true);
76
77 // ...and wait on it.
78 sev().wait();
79
80 return CL_SUCCESS;
81
82 } catch (error &e) {
83 return e.get();
84 }
85
86 CLOVER_API cl_int
clGetEventInfo(cl_event d_ev,cl_event_info param,size_t size,void * r_buf,size_t * r_size)87 clGetEventInfo(cl_event d_ev, cl_event_info param,
88 size_t size, void *r_buf, size_t *r_size) try {
89 property_buffer buf { r_buf, size, r_size };
90 auto &ev = obj(d_ev);
91
92 switch (param) {
93 case CL_EVENT_COMMAND_QUEUE:
94 buf.as_scalar<cl_command_queue>() = desc(ev.queue());
95 break;
96
97 case CL_EVENT_CONTEXT:
98 buf.as_scalar<cl_context>() = desc(ev.context());
99 break;
100
101 case CL_EVENT_COMMAND_TYPE:
102 buf.as_scalar<cl_command_type>() = ev.command();
103 break;
104
105 case CL_EVENT_COMMAND_EXECUTION_STATUS:
106 buf.as_scalar<cl_int>() = ev.status();
107 break;
108
109 case CL_EVENT_REFERENCE_COUNT:
110 buf.as_scalar<cl_uint>() = ev.ref_count();
111 break;
112
113 default:
114 throw error(CL_INVALID_VALUE);
115 }
116
117 return CL_SUCCESS;
118
119 } catch (error &e) {
120 return e.get();
121 }
122
123 CLOVER_API cl_int
clSetEventCallback(cl_event d_ev,cl_int type,void (CL_CALLBACK * pfn_notify)(cl_event,cl_int,void *),void * user_data)124 clSetEventCallback(cl_event d_ev, cl_int type,
125 void (CL_CALLBACK *pfn_notify)(cl_event, cl_int, void *),
126 void *user_data) try {
127 auto &ev = obj(d_ev);
128
129 if (!pfn_notify || type != CL_COMPLETE)
130 throw error(CL_INVALID_VALUE);
131
132 // Create a temporary soft event that depends on ev, with
133 // pfn_notify as completion action.
134 create<soft_event>(ev.context(), ref_vector<event> { ev }, true,
135 [=, &ev](event &) {
136 ev.wait();
137 pfn_notify(desc(ev), ev.status(), user_data);
138 });
139
140 return CL_SUCCESS;
141
142 } catch (error &e) {
143 return e.get();
144 }
145
146 CLOVER_API cl_int
clRetainEvent(cl_event d_ev)147 clRetainEvent(cl_event d_ev) try {
148 obj(d_ev).retain();
149 return CL_SUCCESS;
150
151 } catch (error &e) {
152 return e.get();
153 }
154
155 CLOVER_API cl_int
clReleaseEvent(cl_event d_ev)156 clReleaseEvent(cl_event d_ev) try {
157 if (obj(d_ev).release())
158 delete pobj(d_ev);
159
160 return CL_SUCCESS;
161
162 } catch (error &e) {
163 return e.get();
164 }
165
166 CLOVER_API cl_int
clEnqueueMarker(cl_command_queue d_q,cl_event * rd_ev)167 clEnqueueMarker(cl_command_queue d_q, cl_event *rd_ev) try {
168 auto &q = obj(d_q);
169
170 if (!rd_ev)
171 throw error(CL_INVALID_VALUE);
172
173 *rd_ev = desc(new hard_event(q, CL_COMMAND_MARKER, {}));
174
175 return CL_SUCCESS;
176
177 } catch (error &e) {
178 return e.get();
179 }
180
181 CLOVER_API cl_int
clEnqueueMarkerWithWaitList(cl_command_queue d_q,cl_uint num_deps,const cl_event * d_deps,cl_event * rd_ev)182 clEnqueueMarkerWithWaitList(cl_command_queue d_q, cl_uint num_deps,
183 const cl_event *d_deps, cl_event *rd_ev) try {
184 auto &q = obj(d_q);
185 auto deps = objs<wait_list_tag>(d_deps, num_deps);
186
187 for (auto &ev : deps) {
188 if (ev.context() != q.context())
189 throw error(CL_INVALID_CONTEXT);
190 }
191
192 // Create a hard event that depends on the events in the wait list:
193 // previous commands in the same queue are implicitly serialized
194 // with respect to it -- hard events always are.
195 auto hev = create<hard_event>(q, CL_COMMAND_MARKER, deps);
196
197 ret_object(rd_ev, hev);
198 return CL_SUCCESS;
199
200 } catch (error &e) {
201 return e.get();
202 }
203
204 CLOVER_API cl_int
clEnqueueBarrier(cl_command_queue d_q)205 clEnqueueBarrier(cl_command_queue d_q) try {
206 obj(d_q);
207
208 // No need to do anything, q preserves data ordering strictly.
209
210 return CL_SUCCESS;
211
212 } catch (error &e) {
213 return e.get();
214 }
215
216 CLOVER_API cl_int
clEnqueueBarrierWithWaitList(cl_command_queue d_q,cl_uint num_deps,const cl_event * d_deps,cl_event * rd_ev)217 clEnqueueBarrierWithWaitList(cl_command_queue d_q, cl_uint num_deps,
218 const cl_event *d_deps, cl_event *rd_ev) try {
219 auto &q = obj(d_q);
220 auto deps = objs<wait_list_tag>(d_deps, num_deps);
221
222 for (auto &ev : deps) {
223 if (ev.context() != q.context())
224 throw error(CL_INVALID_CONTEXT);
225 }
226
227 // Create a hard event that depends on the events in the wait list:
228 // subsequent commands in the same queue will be implicitly
229 // serialized with respect to it -- hard events always are.
230 auto hev = create<hard_event>(q, CL_COMMAND_BARRIER, deps);
231
232 ret_object(rd_ev, hev);
233 return CL_SUCCESS;
234
235 } catch (error &e) {
236 return e.get();
237 }
238
239 CLOVER_API cl_int
clEnqueueWaitForEvents(cl_command_queue d_q,cl_uint num_evs,const cl_event * d_evs)240 clEnqueueWaitForEvents(cl_command_queue d_q, cl_uint num_evs,
241 const cl_event *d_evs) try {
242 // The wait list is mandatory for clEnqueueWaitForEvents().
243 objs(d_evs, num_evs);
244
245 return clEnqueueBarrierWithWaitList(d_q, num_evs, d_evs, NULL);
246
247 } catch (error &e) {
248 return e.get();
249 }
250
251 CLOVER_API cl_int
clGetEventProfilingInfo(cl_event d_ev,cl_profiling_info param,size_t size,void * r_buf,size_t * r_size)252 clGetEventProfilingInfo(cl_event d_ev, cl_profiling_info param,
253 size_t size, void *r_buf, size_t *r_size) try {
254 property_buffer buf { r_buf, size, r_size };
255 hard_event &hev = dynamic_cast<hard_event &>(obj(d_ev));
256
257 if (hev.status() != CL_COMPLETE)
258 throw error(CL_PROFILING_INFO_NOT_AVAILABLE);
259
260 switch (param) {
261 case CL_PROFILING_COMMAND_QUEUED:
262 buf.as_scalar<cl_ulong>() = hev.time_queued();
263 break;
264
265 case CL_PROFILING_COMMAND_SUBMIT:
266 buf.as_scalar<cl_ulong>() = hev.time_submit();
267 break;
268
269 case CL_PROFILING_COMMAND_START:
270 buf.as_scalar<cl_ulong>() = hev.time_start();
271 break;
272
273 case CL_PROFILING_COMMAND_END:
274 buf.as_scalar<cl_ulong>() = hev.time_end();
275 break;
276
277 default:
278 throw error(CL_INVALID_VALUE);
279 }
280
281 return CL_SUCCESS;
282
283 } catch (std::bad_cast &e) {
284 return CL_PROFILING_INFO_NOT_AVAILABLE;
285
286 } catch (lazy<cl_ulong>::undefined_error &e) {
287 return CL_PROFILING_INFO_NOT_AVAILABLE;
288
289 } catch (error &e) {
290 return e.get();
291 }
292
293 CLOVER_API cl_int
clFinish(cl_command_queue d_q)294 clFinish(cl_command_queue d_q) try {
295 auto &q = obj(d_q);
296
297 // Create a temporary hard event -- it implicitly depends on all
298 // the previously queued hard events.
299 auto hev = create<hard_event>(q, 0, ref_vector<event> {});
300
301 // And wait on it.
302 hev().wait();
303
304 return CL_SUCCESS;
305
306 } catch (error &e) {
307 return e.get();
308 }
309