From: Zhao Liu <zhao1.liu@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-devel@nongnu.org, qemu-rust@nongnu.org,
Zhao Liu <zhao1.liu@intel.com>
Subject: [PATCH v2 10/14] rust/vmstate: Support vmstate_validate
Date: Tue, 18 Mar 2025 16:32:44 +0800 [thread overview]
Message-ID: <20250318083248.1402990-11-zhao1.liu@intel.com> (raw)
In-Reply-To: <20250318083248.1402990-1-zhao1.liu@intel.com>
In C version, VMSTATE_VALIDATE accepts the function pointer, which is
used to check if some conditions of structure could meet, although the
C version macro doesn't accept any structure as the opaque type.
But it's hard to integrate VMSTATE_VALIDAE into vmstate_struct, a new
macro has to be introduced to specifically handle the case corresponding
to VMSTATE_VALIDATE.
One of the difficulties is inferring the type of a callback by its name
`test_fn`. We can't directly use `test_fn` as a parameter of
test_cb_builder__() to get its type "F", because in this way, Rust
compiler will be too conservative on drop check and complain "the
destructor for this type cannot be evaluated in constant functions".
Fortunately, PhantomData<T> could help in this case, because it is
considered to never have a destructor, no matter its field type [*].
The `phantom__()` in the `call_func_with_field` macro provides a good
example of using PhantomData to infer type. So copy this idea and apply
it to the `vmstate_validate` macro.
Additionally, add a `with_exist_check()` method to help add callback
in future.
[*]: https://doc.rust-lang.org/std/ops/trait.Drop.html#drop-check
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
Changes since v1:
* Rename `with_exist_check()` to `with_validate_flag()`.
* Add a `with_exist_check()` method to help add field_exists callback,
though it can't be used in static VMStateDescription definition but
will be useful for vmstate builder.
---
rust/qemu-api/src/vmstate.rs | 72 +++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs
index 01f06ed7379e..62a0308014e3 100644
--- a/rust/qemu-api/src/vmstate.rs
+++ b/rust/qemu-api/src/vmstate.rs
@@ -25,9 +25,12 @@
//! functionality that is missing from `vmstate_of!`.
use core::{marker::PhantomData, mem, ptr::NonNull};
+use std::os::raw::{c_int, c_void};
pub use crate::bindings::{VMStateDescription, VMStateField};
-use crate::{bindings::VMStateFlags, prelude::*, qom::Owned, zeroable::Zeroable};
+use crate::{
+ bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zeroable::Zeroable,
+};
/// This macro is used to call a function with a generic argument bound
/// to the type of a field. The function must take a
@@ -291,6 +294,30 @@ pub const fn with_varray_multiply(mut self, num: u32) -> VMStateField {
self.num = num as i32;
self
}
+
+ #[must_use]
+ pub const fn with_validate_flag(mut self) -> Self {
+ assert!(self.flags.0 == 0);
+ self.flags = VMStateFlags(VMStateFlags::VMS_MUST_EXIST.0 | VMStateFlags::VMS_ARRAY.0);
+ self.num = 0; // 0 elements: no data, only run test_fn callback
+ self
+ }
+
+ // FIXME: Unfortunately, this non-const fn cannot currently be called in a
+ // static context. Also, it can't be const because the compiler complains
+ // about "constant functions cannot evaluate destructors" for `F`. Add it
+ // for future vmstate builder.
+ #[must_use]
+ pub fn with_exist_check<T, F>(mut self, _cb: F) -> Self
+ where
+ F: for<'a> FnCall<(&'a T, u8), bool>,
+ {
+ assert!(self.field_exists.is_none());
+ let _: () = F::ASSERT_IS_SOME;
+
+ self.field_exists = Some(rust_vms_test_field_exists::<T, F>);
+ self
+ }
}
/// This macro can be used (by just passing it a type) to forward the `VMState`
@@ -508,6 +535,49 @@ macro_rules! vmstate_fields {
}}
}
+pub extern "C" fn rust_vms_test_field_exists<T, F: for<'a> FnCall<(&'a T, u8), bool>>(
+ opaque: *mut c_void,
+ version_id: c_int,
+) -> bool {
+ let owner: &T = unsafe { &*(opaque.cast::<T>()) };
+ let version: u8 = version_id.try_into().unwrap();
+ // SAFETY: the opaque was passed as a reference to `T`.
+ F::call((owner, version))
+}
+
+pub type VMSFieldExistCb = unsafe extern "C" fn(
+ opaque: *mut std::os::raw::c_void,
+ version_id: std::os::raw::c_int,
+) -> bool;
+
+#[doc(alias = "VMSTATE_VALIDATE")]
+#[macro_export]
+macro_rules! vmstate_validate {
+ ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => {
+ $crate::bindings::VMStateField {
+ name: ::std::ffi::CStr::as_ptr($test_name),
+ field_exists: {
+ const fn test_cb_builder__<
+ T,
+ F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>,
+ >(
+ _phantom: ::core::marker::PhantomData<F>,
+ ) -> $crate::vmstate::VMSFieldExistCb {
+ let _: () = F::ASSERT_IS_SOME;
+ $crate::vmstate::rust_vms_test_field_exists::<T, F>
+ }
+
+ const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> {
+ ::core::marker::PhantomData
+ }
+ Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn)))
+ },
+ ..$crate::zeroable::Zeroable::ZERO
+ }
+ .with_validate_flag()
+ };
+}
+
/// A transparent wrapper type for the `subsections` field of
/// [`VMStateDescription`].
///
--
2.34.1
next prev parent reply other threads:[~2025-03-18 8:14 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-18 8:32 [PATCH v2 00/14] rust/vmstate: Clean up, fix, enhance & test Zhao Liu
2025-03-18 8:32 ` [PATCH v2 01/14] rust/vmstate: Remove unnecessary unsafe Zhao Liu
2025-03-18 8:32 ` [PATCH v2 02/14] rust/vmstate: Fix num_offset in vmstate macros Zhao Liu
2025-03-18 8:32 ` [PATCH v2 03/14] rust/vmstate: Fix num field when varray flags are set Zhao Liu
2025-03-18 8:32 ` [PATCH v2 04/14] rust/vmstate: Fix size field of VMStateField with VMS_ARRAY_OF_POINTER flag Zhao Liu
2025-03-18 8:32 ` [PATCH v2 05/14] rust/vmstate: Fix type check for varray in vmstate_struct Zhao Liu
2025-03-18 8:32 ` [PATCH v2 06/14] rust/vmstate: Fix "cannot infer type" error " Zhao Liu
2025-03-18 8:32 ` [PATCH v2 07/14] rust/vmstate: Fix unnecessary VMState bound of with_varray_flag() Zhao Liu
2025-03-18 8:32 ` [PATCH v2 08/14] rust/vmstate: Relax array check when build varray in vmstate_struct Zhao Liu
2025-03-18 8:32 ` [PATCH v2 09/14] rust/vmstate: Re-implement VMState trait for timer binding Zhao Liu
2025-03-18 8:32 ` Zhao Liu [this message]
2025-03-18 10:11 ` [PATCH v2 10/14] rust/vmstate: Support vmstate_validate Paolo Bonzini
2025-03-18 12:23 ` Zhao Liu
2025-03-18 12:32 ` Paolo Bonzini
2025-03-18 13:07 ` Zhao Liu
2025-03-18 8:32 ` [PATCH v2 11/14] rust/vmstate: Add unit test for vmstate_of macro Zhao Liu
2025-03-18 8:32 ` [PATCH v2 12/14] rust/vmstate: Add unit test for vmstate_{of|struct} macro Zhao Liu
2025-03-18 8:32 ` [PATCH v2 13/14] rust/vmstate: Add unit test for pointer case Zhao Liu
2025-03-18 8:32 ` [PATCH v2 14/14] rust/vmstate: Add unit test for vmstate_validate Zhao Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250318083248.1402990-11-zhao1.liu@intel.com \
--to=zhao1.liu@intel.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-rust@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).