1 use crate::api::icd::*;
2 use crate::api::types::*;
3 use crate::api::util::*;
4 use crate::core::context::*;
5 use crate::core::event::*;
6 use crate::core::queue::*;
7
8 use rusticl_opencl_gen::*;
9 use rusticl_proc_macros::cl_entrypoint;
10 use rusticl_proc_macros::cl_info_entrypoint;
11
12 use std::collections::HashSet;
13 use std::ptr;
14 use std::sync::Arc;
15
16 #[cl_info_entrypoint(clGetEventInfo)]
17 unsafe impl CLInfo<cl_event_info> for cl_event {
query(&self, q: cl_event_info, v: CLInfoValue) -> CLResult<CLInfoRes>18 fn query(&self, q: cl_event_info, v: CLInfoValue) -> CLResult<CLInfoRes> {
19 let event = Event::ref_from_raw(*self)?;
20 match *q {
21 CL_EVENT_COMMAND_EXECUTION_STATUS => v.write::<cl_int>(event.status()),
22 CL_EVENT_CONTEXT => {
23 // Note we use as_ptr here which doesn't increase the reference count.
24 let ptr = Arc::as_ptr(&event.context);
25 v.write::<cl_context>(cl_context::from_ptr(ptr))
26 }
27 CL_EVENT_COMMAND_QUEUE => {
28 let ptr = match event.queue.as_ref() {
29 // Note we use as_ptr here which doesn't increase the reference count.
30 Some(queue) => Arc::as_ptr(queue),
31 None => ptr::null_mut(),
32 };
33 v.write::<cl_command_queue>(cl_command_queue::from_ptr(ptr))
34 }
35 CL_EVENT_REFERENCE_COUNT => v.write::<cl_uint>(Event::refcnt(*self)?),
36 CL_EVENT_COMMAND_TYPE => v.write::<cl_command_type>(event.cmd_type),
37 _ => Err(CL_INVALID_VALUE),
38 }
39 }
40 }
41
42 #[cl_info_entrypoint(clGetEventProfilingInfo)]
43 unsafe impl CLInfo<cl_profiling_info> for cl_event {
query(&self, q: cl_profiling_info, v: CLInfoValue) -> CLResult<CLInfoRes>44 fn query(&self, q: cl_profiling_info, v: CLInfoValue) -> CLResult<CLInfoRes> {
45 let event = Event::ref_from_raw(*self)?;
46 if event.cmd_type == CL_COMMAND_USER {
47 // CL_PROFILING_INFO_NOT_AVAILABLE [...] if event is a user event object.
48 return Err(CL_PROFILING_INFO_NOT_AVAILABLE);
49 }
50
51 match *q {
52 CL_PROFILING_COMMAND_QUEUED => v.write::<cl_ulong>(event.get_time(EventTimes::Queued)),
53 CL_PROFILING_COMMAND_SUBMIT => v.write::<cl_ulong>(event.get_time(EventTimes::Submit)),
54 CL_PROFILING_COMMAND_START => v.write::<cl_ulong>(event.get_time(EventTimes::Start)),
55 CL_PROFILING_COMMAND_END => v.write::<cl_ulong>(event.get_time(EventTimes::End)),
56 // For now, we treat Complete the same as End
57 CL_PROFILING_COMMAND_COMPLETE => v.write::<cl_ulong>(event.get_time(EventTimes::End)),
58 _ => Err(CL_INVALID_VALUE),
59 }
60 }
61 }
62
63 #[cl_entrypoint(clCreateUserEvent)]
create_user_event(context: cl_context) -> CLResult<cl_event>64 fn create_user_event(context: cl_context) -> CLResult<cl_event> {
65 let c = Context::arc_from_raw(context)?;
66 Ok(Event::new_user(c).into_cl())
67 }
68
69 #[cl_entrypoint(clRetainEvent)]
retain_event(event: cl_event) -> CLResult<()>70 fn retain_event(event: cl_event) -> CLResult<()> {
71 Event::retain(event)
72 }
73
74 #[cl_entrypoint(clReleaseEvent)]
release_event(event: cl_event) -> CLResult<()>75 fn release_event(event: cl_event) -> CLResult<()> {
76 Event::release(event)
77 }
78
79 #[cl_entrypoint(clWaitForEvents)]
wait_for_events(num_events: cl_uint, event_list: *const cl_event) -> CLResult<()>80 fn wait_for_events(num_events: cl_uint, event_list: *const cl_event) -> CLResult<()> {
81 let evs = Event::arcs_from_arr(event_list, num_events)?;
82
83 // CL_INVALID_VALUE if num_events is zero or event_list is NULL.
84 if evs.is_empty() {
85 return Err(CL_INVALID_VALUE);
86 }
87
88 // CL_INVALID_CONTEXT if events specified in event_list do not belong to the same context.
89 let contexts: HashSet<_> = evs.iter().map(|e| &e.context).collect();
90 if contexts.len() != 1 {
91 return Err(CL_INVALID_CONTEXT);
92 }
93
94 // find all queues we have to flush
95 for q in Event::deep_unflushed_queues(&evs) {
96 q.flush(false)?;
97 }
98
99 // now wait on all events and check if we got any errors
100 let mut err = false;
101 for e in evs {
102 err |= e.wait() < 0;
103 }
104
105 // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the execution status of any of the events
106 // in event_list is a negative integer value.
107 if err {
108 return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
109 }
110
111 Ok(())
112 }
113
114 #[cl_entrypoint(clSetEventCallback)]
set_event_callback( event: cl_event, command_exec_callback_type: cl_int, pfn_event_notify: Option<FuncEventCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()>115 fn set_event_callback(
116 event: cl_event,
117 command_exec_callback_type: cl_int,
118 pfn_event_notify: Option<FuncEventCB>,
119 user_data: *mut ::std::os::raw::c_void,
120 ) -> CLResult<()> {
121 let e = Event::ref_from_raw(event)?;
122
123 // CL_INVALID_VALUE [...] if command_exec_callback_type is not CL_SUBMITTED, CL_RUNNING, or CL_COMPLETE.
124 if ![CL_SUBMITTED, CL_RUNNING, CL_COMPLETE].contains(&(command_exec_callback_type as cl_uint)) {
125 return Err(CL_INVALID_VALUE);
126 }
127
128 // SAFETY: The requirements on `EventCB::new` match the requirements
129 // imposed by the OpenCL specification. It is the caller's duty to uphold them.
130 let cb = unsafe { EventCB::new(pfn_event_notify, user_data)? };
131
132 e.add_cb(command_exec_callback_type, cb);
133
134 Ok(())
135 }
136
137 #[cl_entrypoint(clSetUserEventStatus)]
set_user_event_status(event: cl_event, execution_status: cl_int) -> CLResult<()>138 fn set_user_event_status(event: cl_event, execution_status: cl_int) -> CLResult<()> {
139 let e = Event::ref_from_raw(event)?;
140
141 // CL_INVALID_VALUE if the execution_status is not CL_COMPLETE or a negative integer value.
142 if execution_status != CL_COMPLETE as cl_int && execution_status > 0 {
143 return Err(CL_INVALID_VALUE);
144 }
145
146 // CL_INVALID_OPERATION if the execution_status for event has already been changed by a
147 // previous call to clSetUserEventStatus.
148 if e.status() != CL_SUBMITTED as cl_int {
149 return Err(CL_INVALID_OPERATION);
150 }
151
152 e.set_user_status(execution_status);
153 Ok(())
154 }
155
156 /// implements CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST when `block = true`
create_and_queue( q: Arc<Queue>, cmd_type: cl_command_type, deps: Vec<Arc<Event>>, event: *mut cl_event, block: bool, work: EventSig, ) -> CLResult<()>157 pub fn create_and_queue(
158 q: Arc<Queue>,
159 cmd_type: cl_command_type,
160 deps: Vec<Arc<Event>>,
161 event: *mut cl_event,
162 block: bool,
163 work: EventSig,
164 ) -> CLResult<()> {
165 let e = Event::new(&q, cmd_type, deps, work);
166 if !event.is_null() {
167 // SAFETY: we check for null and valid API use is to pass in a valid pointer
168 unsafe {
169 event.write(Arc::clone(&e).into_cl());
170 }
171 }
172 if block {
173 q.queue(Arc::clone(&e));
174 q.flush(true)?;
175 if e.deps.iter().any(|dep| dep.is_error()) {
176 return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
177 }
178 // return any execution errors when blocking
179 let err = e.status();
180 if err < 0 {
181 return Err(err);
182 }
183 } else {
184 q.queue(e);
185 }
186 Ok(())
187 }
188