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
26using namespace clover;
27
28CLOVER_API cl_event
29clCreateUserEvent(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
40CLOVER_API cl_int
41clSetUserEventStatus(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
61CLOVER_API cl_int
62clWaitForEvents(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
86CLOVER_API cl_int
87clGetEventInfo(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
123CLOVER_API cl_int
124clSetEventCallback(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
147CLOVER_API cl_int
148clRetainEvent(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
156CLOVER_API cl_int
157clReleaseEvent(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
167CLOVER_API cl_int
168clEnqueueMarker(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
182CLOVER_API cl_int
183clEnqueueMarkerWithWaitList(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
205CLOVER_API cl_int
206clEnqueueBarrier(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
217CLOVER_API cl_int
218clEnqueueBarrierWithWaitList(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
240CLOVER_API cl_int
241clEnqueueWaitForEvents(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
252CLOVER_API cl_int
253clGetEventProfilingInfo(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   case CL_PROFILING_COMMAND_COMPLETE:
276      buf.as_scalar<cl_ulong>() = hev.time_end();
277      break;
278
279   default:
280      throw error(CL_INVALID_VALUE);
281   }
282
283   return CL_SUCCESS;
284
285} catch (std::bad_cast &) {
286   return CL_PROFILING_INFO_NOT_AVAILABLE;
287
288} catch (lazy<cl_ulong>::undefined_error &) {
289   return CL_PROFILING_INFO_NOT_AVAILABLE;
290
291} catch (error &e) {
292   return e.get();
293}
294
295CLOVER_API cl_int
296clFinish(cl_command_queue d_q) try {
297   auto &q = obj(d_q);
298
299   // Create a temporary hard event -- it implicitly depends on all
300   // the previously queued hard events.
301   auto hev = create<hard_event>(q, 0, ref_vector<event> {});
302
303   // And wait on it.
304   hev().wait();
305
306   return CL_SUCCESS;
307
308} catch (error &e) {
309   return e.get();
310}
311