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 ||
130 (type != CL_COMPLETE && type != CL_SUBMITTED && type != CL_RUNNING))
131 throw error(CL_INVALID_VALUE);
132
133 // Create a temporary soft event that depends on ev, with
134 // pfn_notify as completion action.
135 create<soft_event>(ev.context(), ref_vector<event> { ev }, true,
136 [=, &ev](event &) {
137 ev.wait();
138 pfn_notify(desc(ev), ev.status(), user_data);
139 });
140
141 return CL_SUCCESS;
142
143 } catch (error &e) {
144 return e.get();
145 }
146
147 CLOVER_API cl_int
clRetainEvent(cl_event d_ev)148 clRetainEvent(cl_event d_ev) try {
149 obj(d_ev).retain();
150 return CL_SUCCESS;
151
152 } catch (error &e) {
153 return e.get();
154 }
155
156 CLOVER_API cl_int
clReleaseEvent(cl_event d_ev)157 clReleaseEvent(cl_event d_ev) try {
158 if (obj(d_ev).release())
159 delete pobj(d_ev);
160
161 return CL_SUCCESS;
162
163 } catch (error &e) {
164 return e.get();
165 }
166
167 CLOVER_API cl_int
clEnqueueMarker(cl_command_queue d_q,cl_event * rd_ev)168 clEnqueueMarker(cl_command_queue d_q, cl_event *rd_ev) try {
169 auto &q = obj(d_q);
170
171 if (!rd_ev)
172 throw error(CL_INVALID_VALUE);
173
174 *rd_ev = desc(new hard_event(q, CL_COMMAND_MARKER, {}));
175
176 return CL_SUCCESS;
177
178 } catch (error &e) {
179 return e.get();
180 }
181
182 CLOVER_API cl_int
clEnqueueMarkerWithWaitList(cl_command_queue d_q,cl_uint num_deps,const cl_event * d_deps,cl_event * rd_ev)183 clEnqueueMarkerWithWaitList(cl_command_queue d_q, cl_uint num_deps,
184 const cl_event *d_deps, cl_event *rd_ev) try {
185 auto &q = obj(d_q);
186 auto deps = objs<wait_list_tag>(d_deps, num_deps);
187
188 for (auto &ev : deps) {
189 if (ev.context() != q.context())
190 throw error(CL_INVALID_CONTEXT);
191 }
192
193 // Create a hard event that depends on the events in the wait list:
194 // previous commands in the same queue are implicitly serialized
195 // with respect to it -- hard events always are.
196 auto hev = create<hard_event>(q, CL_COMMAND_MARKER, deps);
197
198 ret_object(rd_ev, hev);
199 return CL_SUCCESS;
200
201 } catch (error &e) {
202 return e.get();
203 }
204
205 CLOVER_API cl_int
clEnqueueBarrier(cl_command_queue d_q)206 clEnqueueBarrier(cl_command_queue d_q) try {
207 obj(d_q);
208
209 // No need to do anything, q preserves data ordering strictly.
210
211 return CL_SUCCESS;
212
213 } catch (error &e) {
214 return e.get();
215 }
216
217 CLOVER_API cl_int
clEnqueueBarrierWithWaitList(cl_command_queue d_q,cl_uint num_deps,const cl_event * d_deps,cl_event * rd_ev)218 clEnqueueBarrierWithWaitList(cl_command_queue d_q, cl_uint num_deps,
219 const cl_event *d_deps, cl_event *rd_ev) try {
220 auto &q = obj(d_q);
221 auto deps = objs<wait_list_tag>(d_deps, num_deps);
222
223 for (auto &ev : deps) {
224 if (ev.context() != q.context())
225 throw error(CL_INVALID_CONTEXT);
226 }
227
228 // Create a hard event that depends on the events in the wait list:
229 // subsequent commands in the same queue will be implicitly
230 // serialized with respect to it -- hard events always are.
231 auto hev = create<hard_event>(q, CL_COMMAND_BARRIER, deps);
232
233 ret_object(rd_ev, hev);
234 return CL_SUCCESS;
235
236 } catch (error &e) {
237 return e.get();
238 }
239
240 CLOVER_API cl_int
clEnqueueWaitForEvents(cl_command_queue d_q,cl_uint num_evs,const cl_event * d_evs)241 clEnqueueWaitForEvents(cl_command_queue d_q, cl_uint num_evs,
242 const cl_event *d_evs) try {
243 // The wait list is mandatory for clEnqueueWaitForEvents().
244 objs(d_evs, num_evs);
245
246 return clEnqueueBarrierWithWaitList(d_q, num_evs, d_evs, NULL);
247
248 } catch (error &e) {
249 return e.get();
250 }
251
252 CLOVER_API cl_int
clGetEventProfilingInfo(cl_event d_ev,cl_profiling_info param,size_t size,void * r_buf,size_t * r_size)253 clGetEventProfilingInfo(cl_event d_ev, cl_profiling_info param,
254 size_t size, void *r_buf, size_t *r_size) try {
255 property_buffer buf { r_buf, size, r_size };
256 hard_event &hev = dynamic_cast<hard_event &>(obj(d_ev));
257
258 if (hev.status() != CL_COMPLETE)
259 throw error(CL_PROFILING_INFO_NOT_AVAILABLE);
260
261 switch (param) {
262 case CL_PROFILING_COMMAND_QUEUED:
263 buf.as_scalar<cl_ulong>() = hev.time_queued();
264 break;
265
266 case CL_PROFILING_COMMAND_SUBMIT:
267 buf.as_scalar<cl_ulong>() = hev.time_submit();
268 break;
269
270 case CL_PROFILING_COMMAND_START:
271 buf.as_scalar<cl_ulong>() = hev.time_start();
272 break;
273
274 case CL_PROFILING_COMMAND_END:
275 buf.as_scalar<cl_ulong>() = hev.time_end();
276 break;
277
278 default:
279 throw error(CL_INVALID_VALUE);
280 }
281
282 return CL_SUCCESS;
283
284 } catch (std::bad_cast &e) {
285 return CL_PROFILING_INFO_NOT_AVAILABLE;
286
287 } catch (lazy<cl_ulong>::undefined_error &e) {
288 return CL_PROFILING_INFO_NOT_AVAILABLE;
289
290 } catch (error &e) {
291 return e.get();
292 }
293
294 CLOVER_API cl_int
clFinish(cl_command_queue d_q)295 clFinish(cl_command_queue d_q) try {
296 auto &q = obj(d_q);
297
298 // Create a temporary hard event -- it implicitly depends on all
299 // the previously queued hard events.
300 auto hev = create<hard_event>(q, 0, ref_vector<event> {});
301
302 // And wait on it.
303 hev().wait();
304
305 return CL_SUCCESS;
306
307 } catch (error &e) {
308 return e.get();
309 }
310