17ec681f3Smrg// 27ec681f3Smrg// Copyright 2012 Francisco Jerez 37ec681f3Smrg// 47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg// copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg// to deal in the Software without restriction, including without limitation 77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg// Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg// 117ec681f3Smrg// The above copyright notice and this permission notice shall be included in 127ec681f3Smrg// all copies or substantial portions of the Software. 137ec681f3Smrg// 147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE. 217ec681f3Smrg// 227ec681f3Smrg 237ec681f3Smrg#include "api/util.hpp" 247ec681f3Smrg#include "core/event.hpp" 257ec681f3Smrg 267ec681f3Smrgusing namespace clover; 277ec681f3Smrg 287ec681f3SmrgCLOVER_API cl_event 297ec681f3SmrgclCreateUserEvent(cl_context d_ctx, cl_int *r_errcode) try { 307ec681f3Smrg auto &ctx = obj(d_ctx); 317ec681f3Smrg 327ec681f3Smrg ret_error(r_errcode, CL_SUCCESS); 337ec681f3Smrg return desc(new soft_event(ctx, {}, false)); 347ec681f3Smrg 357ec681f3Smrg} catch (error &e) { 367ec681f3Smrg ret_error(r_errcode, e); 377ec681f3Smrg return NULL; 387ec681f3Smrg} 397ec681f3Smrg 407ec681f3SmrgCLOVER_API cl_int 417ec681f3SmrgclSetUserEventStatus(cl_event d_ev, cl_int status) try { 427ec681f3Smrg auto &sev = obj<soft_event>(d_ev); 437ec681f3Smrg 447ec681f3Smrg if (status > 0) 457ec681f3Smrg return CL_INVALID_VALUE; 467ec681f3Smrg 477ec681f3Smrg if (sev.status() <= 0) 487ec681f3Smrg return CL_INVALID_OPERATION; 497ec681f3Smrg 507ec681f3Smrg if (status) 517ec681f3Smrg sev.abort(status); 527ec681f3Smrg else 537ec681f3Smrg sev.trigger(); 547ec681f3Smrg 557ec681f3Smrg return CL_SUCCESS; 567ec681f3Smrg 577ec681f3Smrg} catch (error &e) { 587ec681f3Smrg return e.get(); 597ec681f3Smrg} 607ec681f3Smrg 617ec681f3SmrgCLOVER_API cl_int 627ec681f3SmrgclWaitForEvents(cl_uint num_evs, const cl_event *d_evs) try { 637ec681f3Smrg auto evs = objs(d_evs, num_evs); 647ec681f3Smrg 657ec681f3Smrg for (auto &ev : evs) { 667ec681f3Smrg if (ev.context() != evs.front().context()) 677ec681f3Smrg throw error(CL_INVALID_CONTEXT); 687ec681f3Smrg 697ec681f3Smrg if (ev.status() < 0) 707ec681f3Smrg throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST); 717ec681f3Smrg } 727ec681f3Smrg 737ec681f3Smrg // Create a temporary soft event that depends on all the events in 747ec681f3Smrg // the wait list 757ec681f3Smrg auto sev = create<soft_event>(evs.front().context(), evs, true); 767ec681f3Smrg 777ec681f3Smrg // ...and wait on it. 787ec681f3Smrg sev().wait(); 797ec681f3Smrg 807ec681f3Smrg return CL_SUCCESS; 817ec681f3Smrg 827ec681f3Smrg} catch (error &e) { 837ec681f3Smrg return e.get(); 847ec681f3Smrg} 857ec681f3Smrg 867ec681f3SmrgCLOVER_API cl_int 877ec681f3SmrgclGetEventInfo(cl_event d_ev, cl_event_info param, 887ec681f3Smrg size_t size, void *r_buf, size_t *r_size) try { 897ec681f3Smrg property_buffer buf { r_buf, size, r_size }; 907ec681f3Smrg auto &ev = obj(d_ev); 917ec681f3Smrg 927ec681f3Smrg switch (param) { 937ec681f3Smrg case CL_EVENT_COMMAND_QUEUE: 947ec681f3Smrg buf.as_scalar<cl_command_queue>() = desc(ev.queue()); 957ec681f3Smrg break; 967ec681f3Smrg 977ec681f3Smrg case CL_EVENT_CONTEXT: 987ec681f3Smrg buf.as_scalar<cl_context>() = desc(ev.context()); 997ec681f3Smrg break; 1007ec681f3Smrg 1017ec681f3Smrg case CL_EVENT_COMMAND_TYPE: 1027ec681f3Smrg buf.as_scalar<cl_command_type>() = ev.command(); 1037ec681f3Smrg break; 1047ec681f3Smrg 1057ec681f3Smrg case CL_EVENT_COMMAND_EXECUTION_STATUS: 1067ec681f3Smrg buf.as_scalar<cl_int>() = ev.status(); 1077ec681f3Smrg break; 1087ec681f3Smrg 1097ec681f3Smrg case CL_EVENT_REFERENCE_COUNT: 1107ec681f3Smrg buf.as_scalar<cl_uint>() = ev.ref_count(); 1117ec681f3Smrg break; 1127ec681f3Smrg 1137ec681f3Smrg default: 1147ec681f3Smrg throw error(CL_INVALID_VALUE); 1157ec681f3Smrg } 1167ec681f3Smrg 1177ec681f3Smrg return CL_SUCCESS; 1187ec681f3Smrg 1197ec681f3Smrg} catch (error &e) { 1207ec681f3Smrg return e.get(); 1217ec681f3Smrg} 1227ec681f3Smrg 1237ec681f3SmrgCLOVER_API cl_int 1247ec681f3SmrgclSetEventCallback(cl_event d_ev, cl_int type, 1257ec681f3Smrg void (CL_CALLBACK *pfn_notify)(cl_event, cl_int, void *), 1267ec681f3Smrg void *user_data) try { 1277ec681f3Smrg auto &ev = obj(d_ev); 1287ec681f3Smrg 1297ec681f3Smrg if (!pfn_notify || 1307ec681f3Smrg (type != CL_COMPLETE && type != CL_SUBMITTED && type != CL_RUNNING)) 1317ec681f3Smrg throw error(CL_INVALID_VALUE); 1327ec681f3Smrg 1337ec681f3Smrg // Create a temporary soft event that depends on ev, with 1347ec681f3Smrg // pfn_notify as completion action. 1357ec681f3Smrg create<soft_event>(ev.context(), ref_vector<event> { ev }, true, 1367ec681f3Smrg [=, &ev](event &) { 1377ec681f3Smrg ev.wait(); 1387ec681f3Smrg pfn_notify(desc(ev), ev.status(), user_data); 1397ec681f3Smrg }); 1407ec681f3Smrg 1417ec681f3Smrg return CL_SUCCESS; 1427ec681f3Smrg 1437ec681f3Smrg} catch (error &e) { 1447ec681f3Smrg return e.get(); 1457ec681f3Smrg} 1467ec681f3Smrg 1477ec681f3SmrgCLOVER_API cl_int 1487ec681f3SmrgclRetainEvent(cl_event d_ev) try { 1497ec681f3Smrg obj(d_ev).retain(); 1507ec681f3Smrg return CL_SUCCESS; 1517ec681f3Smrg 1527ec681f3Smrg} catch (error &e) { 1537ec681f3Smrg return e.get(); 1547ec681f3Smrg} 1557ec681f3Smrg 1567ec681f3SmrgCLOVER_API cl_int 1577ec681f3SmrgclReleaseEvent(cl_event d_ev) try { 1587ec681f3Smrg if (obj(d_ev).release()) 1597ec681f3Smrg delete pobj(d_ev); 1607ec681f3Smrg 1617ec681f3Smrg return CL_SUCCESS; 1627ec681f3Smrg 1637ec681f3Smrg} catch (error &e) { 1647ec681f3Smrg return e.get(); 1657ec681f3Smrg} 1667ec681f3Smrg 1677ec681f3SmrgCLOVER_API cl_int 1687ec681f3SmrgclEnqueueMarker(cl_command_queue d_q, cl_event *rd_ev) try { 1697ec681f3Smrg auto &q = obj(d_q); 1707ec681f3Smrg 1717ec681f3Smrg if (!rd_ev) 1727ec681f3Smrg throw error(CL_INVALID_VALUE); 1737ec681f3Smrg 1747ec681f3Smrg *rd_ev = desc(new hard_event(q, CL_COMMAND_MARKER, {})); 1757ec681f3Smrg 1767ec681f3Smrg return CL_SUCCESS; 1777ec681f3Smrg 1787ec681f3Smrg} catch (error &e) { 1797ec681f3Smrg return e.get(); 1807ec681f3Smrg} 1817ec681f3Smrg 1827ec681f3SmrgCLOVER_API cl_int 1837ec681f3SmrgclEnqueueMarkerWithWaitList(cl_command_queue d_q, cl_uint num_deps, 1847ec681f3Smrg const cl_event *d_deps, cl_event *rd_ev) try { 1857ec681f3Smrg auto &q = obj(d_q); 1867ec681f3Smrg auto deps = objs<wait_list_tag>(d_deps, num_deps); 1877ec681f3Smrg 1887ec681f3Smrg for (auto &ev : deps) { 1897ec681f3Smrg if (ev.context() != q.context()) 1907ec681f3Smrg throw error(CL_INVALID_CONTEXT); 1917ec681f3Smrg } 1927ec681f3Smrg 1937ec681f3Smrg // Create a hard event that depends on the events in the wait list: 1947ec681f3Smrg // previous commands in the same queue are implicitly serialized 1957ec681f3Smrg // with respect to it -- hard events always are. 1967ec681f3Smrg auto hev = create<hard_event>(q, CL_COMMAND_MARKER, deps); 1977ec681f3Smrg 1987ec681f3Smrg ret_object(rd_ev, hev); 1997ec681f3Smrg return CL_SUCCESS; 2007ec681f3Smrg 2017ec681f3Smrg} catch (error &e) { 2027ec681f3Smrg return e.get(); 2037ec681f3Smrg} 2047ec681f3Smrg 2057ec681f3SmrgCLOVER_API cl_int 2067ec681f3SmrgclEnqueueBarrier(cl_command_queue d_q) try { 2077ec681f3Smrg obj(d_q); 2087ec681f3Smrg 2097ec681f3Smrg // No need to do anything, q preserves data ordering strictly. 2107ec681f3Smrg 2117ec681f3Smrg return CL_SUCCESS; 2127ec681f3Smrg 2137ec681f3Smrg} catch (error &e) { 2147ec681f3Smrg return e.get(); 2157ec681f3Smrg} 2167ec681f3Smrg 2177ec681f3SmrgCLOVER_API cl_int 2187ec681f3SmrgclEnqueueBarrierWithWaitList(cl_command_queue d_q, cl_uint num_deps, 2197ec681f3Smrg const cl_event *d_deps, cl_event *rd_ev) try { 2207ec681f3Smrg auto &q = obj(d_q); 2217ec681f3Smrg auto deps = objs<wait_list_tag>(d_deps, num_deps); 2227ec681f3Smrg 2237ec681f3Smrg for (auto &ev : deps) { 2247ec681f3Smrg if (ev.context() != q.context()) 2257ec681f3Smrg throw error(CL_INVALID_CONTEXT); 2267ec681f3Smrg } 2277ec681f3Smrg 2287ec681f3Smrg // Create a hard event that depends on the events in the wait list: 2297ec681f3Smrg // subsequent commands in the same queue will be implicitly 2307ec681f3Smrg // serialized with respect to it -- hard events always are. 2317ec681f3Smrg auto hev = create<hard_event>(q, CL_COMMAND_BARRIER, deps); 2327ec681f3Smrg 2337ec681f3Smrg ret_object(rd_ev, hev); 2347ec681f3Smrg return CL_SUCCESS; 2357ec681f3Smrg 2367ec681f3Smrg} catch (error &e) { 2377ec681f3Smrg return e.get(); 2387ec681f3Smrg} 2397ec681f3Smrg 2407ec681f3SmrgCLOVER_API cl_int 2417ec681f3SmrgclEnqueueWaitForEvents(cl_command_queue d_q, cl_uint num_evs, 2427ec681f3Smrg const cl_event *d_evs) try { 2437ec681f3Smrg // The wait list is mandatory for clEnqueueWaitForEvents(). 2447ec681f3Smrg objs(d_evs, num_evs); 2457ec681f3Smrg 2467ec681f3Smrg return clEnqueueBarrierWithWaitList(d_q, num_evs, d_evs, NULL); 2477ec681f3Smrg 2487ec681f3Smrg} catch (error &e) { 2497ec681f3Smrg return e.get(); 2507ec681f3Smrg} 2517ec681f3Smrg 2527ec681f3SmrgCLOVER_API cl_int 2537ec681f3SmrgclGetEventProfilingInfo(cl_event d_ev, cl_profiling_info param, 2547ec681f3Smrg size_t size, void *r_buf, size_t *r_size) try { 2557ec681f3Smrg property_buffer buf { r_buf, size, r_size }; 2567ec681f3Smrg hard_event &hev = dynamic_cast<hard_event &>(obj(d_ev)); 2577ec681f3Smrg 2587ec681f3Smrg if (hev.status() != CL_COMPLETE) 2597ec681f3Smrg throw error(CL_PROFILING_INFO_NOT_AVAILABLE); 2607ec681f3Smrg 2617ec681f3Smrg switch (param) { 2627ec681f3Smrg case CL_PROFILING_COMMAND_QUEUED: 2637ec681f3Smrg buf.as_scalar<cl_ulong>() = hev.time_queued(); 2647ec681f3Smrg break; 2657ec681f3Smrg 2667ec681f3Smrg case CL_PROFILING_COMMAND_SUBMIT: 2677ec681f3Smrg buf.as_scalar<cl_ulong>() = hev.time_submit(); 2687ec681f3Smrg break; 2697ec681f3Smrg 2707ec681f3Smrg case CL_PROFILING_COMMAND_START: 2717ec681f3Smrg buf.as_scalar<cl_ulong>() = hev.time_start(); 2727ec681f3Smrg break; 2737ec681f3Smrg 2747ec681f3Smrg case CL_PROFILING_COMMAND_END: 2757ec681f3Smrg case CL_PROFILING_COMMAND_COMPLETE: 2767ec681f3Smrg buf.as_scalar<cl_ulong>() = hev.time_end(); 2777ec681f3Smrg break; 2787ec681f3Smrg 2797ec681f3Smrg default: 2807ec681f3Smrg throw error(CL_INVALID_VALUE); 2817ec681f3Smrg } 2827ec681f3Smrg 2837ec681f3Smrg return CL_SUCCESS; 2847ec681f3Smrg 2857ec681f3Smrg} catch (std::bad_cast &) { 2867ec681f3Smrg return CL_PROFILING_INFO_NOT_AVAILABLE; 2877ec681f3Smrg 2887ec681f3Smrg} catch (lazy<cl_ulong>::undefined_error &) { 2897ec681f3Smrg return CL_PROFILING_INFO_NOT_AVAILABLE; 2907ec681f3Smrg 2917ec681f3Smrg} catch (error &e) { 2927ec681f3Smrg return e.get(); 2937ec681f3Smrg} 2947ec681f3Smrg 2957ec681f3SmrgCLOVER_API cl_int 2967ec681f3SmrgclFinish(cl_command_queue d_q) try { 2977ec681f3Smrg auto &q = obj(d_q); 2987ec681f3Smrg 2997ec681f3Smrg // Create a temporary hard event -- it implicitly depends on all 3007ec681f3Smrg // the previously queued hard events. 3017ec681f3Smrg auto hev = create<hard_event>(q, 0, ref_vector<event> {}); 3027ec681f3Smrg 3037ec681f3Smrg // And wait on it. 3047ec681f3Smrg hev().wait(); 3057ec681f3Smrg 3067ec681f3Smrg return CL_SUCCESS; 3077ec681f3Smrg 3087ec681f3Smrg} catch (error &e) { 3097ec681f3Smrg return e.get(); 3107ec681f3Smrg} 311