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