• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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