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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 // SOFTWARE.
21 //
22
23 #include "api/util.hpp"
24 #include "core/event.hpp"
25
26 using namespace clover;
27
28 PUBLIC cl_event
clCreateUserEvent(cl_context ctx,cl_int * errcode_ret)29 clCreateUserEvent(cl_context ctx, cl_int *errcode_ret) try {
30 if (!ctx)
31 throw error(CL_INVALID_CONTEXT);
32
33 ret_error(errcode_ret, CL_SUCCESS);
34 return new soft_event(*ctx, {}, false);
35
36 } catch(error &e) {
37 ret_error(errcode_ret, e);
38 return NULL;
39 }
40
41 PUBLIC cl_int
clSetUserEventStatus(cl_event ev,cl_int status)42 clSetUserEventStatus(cl_event ev, cl_int status) {
43 if (!dynamic_cast<soft_event *>(ev))
44 return CL_INVALID_EVENT;
45
46 if (status > 0)
47 return CL_INVALID_VALUE;
48
49 if (ev->status() <= 0)
50 return CL_INVALID_OPERATION;
51
52 if (status)
53 ev->abort(status);
54 else
55 ev->trigger();
56
57 return CL_SUCCESS;
58 }
59
60 PUBLIC cl_int
clWaitForEvents(cl_uint num_evs,const cl_event * evs)61 clWaitForEvents(cl_uint num_evs, const cl_event *evs) try {
62 if (!num_evs || !evs)
63 throw error(CL_INVALID_VALUE);
64
65 std::for_each(evs, evs + num_evs, [&](const cl_event ev) {
66 if (!ev)
67 throw error(CL_INVALID_EVENT);
68
69 if (&ev->ctx != &evs[0]->ctx)
70 throw error(CL_INVALID_CONTEXT);
71
72 if (ev->status() < 0)
73 throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
74 });
75
76 // Create a temporary soft event that depends on all the events in
77 // the wait list
78 ref_ptr<soft_event> sev = transfer(
79 new soft_event(evs[0]->ctx, { evs, evs + num_evs }, true));
80
81 // ...and wait on it.
82 sev->wait();
83
84 return CL_SUCCESS;
85
86 } catch(error &e) {
87 return e.get();
88 }
89
90 PUBLIC cl_int
clGetEventInfo(cl_event ev,cl_event_info param,size_t size,void * buf,size_t * size_ret)91 clGetEventInfo(cl_event ev, cl_event_info param,
92 size_t size, void *buf, size_t *size_ret) {
93 if (!ev)
94 return CL_INVALID_EVENT;
95
96 switch (param) {
97 case CL_EVENT_COMMAND_QUEUE:
98 return scalar_property<cl_command_queue>(buf, size, size_ret, ev->queue());
99
100 case CL_EVENT_CONTEXT:
101 return scalar_property<cl_context>(buf, size, size_ret, &ev->ctx);
102
103 case CL_EVENT_COMMAND_TYPE:
104 return scalar_property<cl_command_type>(buf, size, size_ret, ev->command());
105
106 case CL_EVENT_COMMAND_EXECUTION_STATUS:
107 return scalar_property<cl_int>(buf, size, size_ret, ev->status());
108
109 case CL_EVENT_REFERENCE_COUNT:
110 return scalar_property<cl_uint>(buf, size, size_ret, ev->ref_count());
111
112 default:
113 return CL_INVALID_VALUE;
114 }
115 }
116
117 PUBLIC cl_int
clSetEventCallback(cl_event ev,cl_int type,void (CL_CALLBACK * pfn_event_notify)(cl_event,cl_int,void *),void * user_data)118 clSetEventCallback(cl_event ev, cl_int type,
119 void (CL_CALLBACK *pfn_event_notify)(cl_event, cl_int,
120 void *),
121 void *user_data) try {
122 if (!ev)
123 throw error(CL_INVALID_EVENT);
124
125 if (!pfn_event_notify || type != CL_COMPLETE)
126 throw error(CL_INVALID_VALUE);
127
128 // Create a temporary soft event that depends on ev, with
129 // pfn_event_notify as completion action.
130 ref_ptr<soft_event> sev = transfer(
131 new soft_event(ev->ctx, { ev }, true,
132 [=](event &) {
133 ev->wait();
134 pfn_event_notify(ev, ev->status(), user_data);
135 }));
136
137 return CL_SUCCESS;
138
139 } catch(error &e) {
140 return e.get();
141 }
142
143 PUBLIC cl_int
clRetainEvent(cl_event ev)144 clRetainEvent(cl_event ev) {
145 if (!ev)
146 return CL_INVALID_EVENT;
147
148 ev->retain();
149 return CL_SUCCESS;
150 }
151
152 PUBLIC cl_int
clReleaseEvent(cl_event ev)153 clReleaseEvent(cl_event ev) {
154 if (!ev)
155 return CL_INVALID_EVENT;
156
157 if (ev->release())
158 delete ev;
159
160 return CL_SUCCESS;
161 }
162
163 PUBLIC cl_int
clEnqueueMarker(cl_command_queue q,cl_event * ev)164 clEnqueueMarker(cl_command_queue q, cl_event *ev) try {
165 if (!q)
166 throw error(CL_INVALID_COMMAND_QUEUE);
167
168 if (!ev)
169 throw error(CL_INVALID_VALUE);
170
171 *ev = new hard_event(*q, CL_COMMAND_MARKER, {});
172
173 return CL_SUCCESS;
174
175 } catch(error &e) {
176 return e.get();
177 }
178
179 PUBLIC cl_int
clEnqueueBarrier(cl_command_queue q)180 clEnqueueBarrier(cl_command_queue q) {
181 if (!q)
182 return CL_INVALID_COMMAND_QUEUE;
183
184 // No need to do anything, q preserves data ordering strictly.
185 return CL_SUCCESS;
186 }
187
188 PUBLIC cl_int
clEnqueueWaitForEvents(cl_command_queue q,cl_uint num_evs,const cl_event * evs)189 clEnqueueWaitForEvents(cl_command_queue q, cl_uint num_evs,
190 const cl_event *evs) try {
191 if (!q)
192 throw error(CL_INVALID_COMMAND_QUEUE);
193
194 if (!num_evs || !evs)
195 throw error(CL_INVALID_VALUE);
196
197 std::for_each(evs, evs + num_evs, [&](const cl_event ev) {
198 if (!ev)
199 throw error(CL_INVALID_EVENT);
200
201 if (&ev->ctx != &q->ctx)
202 throw error(CL_INVALID_CONTEXT);
203 });
204
205 // Create a hard event that depends on the events in the wait list:
206 // subsequent commands in the same queue will be implicitly
207 // serialized with respect to it -- hard events always are.
208 ref_ptr<hard_event> hev = transfer(
209 new hard_event(*q, 0, { evs, evs + num_evs }));
210
211 return CL_SUCCESS;
212
213 } catch(error &e) {
214 return e.get();
215 }
216
217 PUBLIC cl_int
clGetEventProfilingInfo(cl_event ev,cl_profiling_info param,size_t size,void * buf,size_t * size_ret)218 clGetEventProfilingInfo(cl_event ev, cl_profiling_info param,
219 size_t size, void *buf, size_t *size_ret) {
220 return CL_PROFILING_INFO_NOT_AVAILABLE;
221 }
222
223 PUBLIC cl_int
clFinish(cl_command_queue q)224 clFinish(cl_command_queue q) try {
225 if (!q)
226 throw error(CL_INVALID_COMMAND_QUEUE);
227
228 // Create a temporary hard event -- it implicitly depends on all
229 // the previously queued hard events.
230 ref_ptr<hard_event> hev = transfer(new hard_event(*q, 0, { }));
231
232 // And wait on it.
233 hev->wait();
234
235 return CL_SUCCESS;
236
237 } catch(error &e) {
238 return e.get();
239 }
240