rusticl: add structs to hold the C callbacks
authorLingMan <18294-LingMan@users.noreply.gitlab.freedesktop.org>
Wed, 11 Oct 2023 19:26:05 +0000 (21:26 +0200)
committerMarge Bot <emma+marge@anholt.net>
Sun, 15 Oct 2023 00:17:10 +0000 (00:17 +0000)
Keeps function pointers and their provided user data together. Since these callbacks are guaranteed
to be thread-safe by the OpenCL spec, they are marked Send and Sync.

Reviewed-by: Karol Herbst <kherbst@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25669>

src/gallium/frontends/rusticl/api/types.rs

index b4a4c1a..b5486a7 100644 (file)
@@ -1,6 +1,9 @@
+use crate::api::icd::CLResult;
+
 use rusticl_opencl_gen::*;
 
 use std::borrow::Borrow;
+use std::ffi::c_void;
 use std::iter::Product;
 
 #[macro_export]
@@ -22,6 +25,53 @@ macro_rules! cl_callback {
         pub type $fn_alias = unsafe extern "C" fn(
             $($p: $ty,)*
         );
+
+        // INVARIANT:
+        // All safety requirements on `func` and `data` documented on `$cb::new` are invariants.
+        pub struct $cb {
+            pub func: $fn_alias,
+            pub data: *mut c_void,
+        }
+
+        #[allow(dead_code)]
+        impl $cb {
+            /// Creates a new `$cb`. Returns `Err(CL_INVALID_VALUE)` if `func` is `None`.
+            ///
+            /// # SAFETY:
+            ///
+            /// If `func` is `None`, there are no safety requirements. Otherwise:
+            ///
+            /// - `func` must be a thread-safe fn.
+            /// - Passing `data` as the last parameter to `func` must not cause unsoundness.
+            pub unsafe fn new(func: Option<$fn_alias>, data: *mut c_void) -> CLResult<Self> {
+                let Some(func) = func else {
+                    return Err(CL_INVALID_VALUE);
+                };
+                Ok(Self { func, data })
+            }
+
+            /// Creates a new Option(`$cb`). Returns:
+            /// - `Ok(Some($cb)) if `func` is `Some(_)`.
+            /// - `Ok(None)` if `func` is `None` and `data` is `null`.
+            /// - `Err(CL_INVALID_VALUE)` if `func` is `None` and `data` is not `null`.
+            ///
+            /// # SAFETY:
+            ///
+            /// The safety requirements are identical to those of [`new`].
+            pub unsafe fn try_new(func: Option<$fn_alias>, data: *mut c_void) -> CLResult<Option<Self>> {
+                let Some(func) = func else {
+                    return if data.is_null() {
+                        Ok(None)
+                    } else {
+                        Err(CL_INVALID_VALUE)
+                    };
+                };
+                Ok(Some(Self { func, data }))
+            }
+        }
+
+        unsafe impl Send for $cb {}
+        unsafe impl Sync for $cb {}
     }
 }