-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dummy PR for proxy bindings #3
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Alexandru Agache <[email protected]>
Signed-off-by: Alexandru Agache <[email protected]>
Signed-off-by: Alexandru Agache <[email protected]>
Once we have run into a trap to separate data structs and their state structs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
use super::*; | ||
|
||
#[test] | ||
fn bindgen_test_layout_kvm_pic_state() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these structs are shadowing the upstream ones, I think the layout tests for them should compare size, alignment, etc against the upstream struct instead of hardcoded values.
This would improve on the mechanisms to keep them in sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, what wasn't clearly presented is the layout tests are actually the ones generated for the upstream bindings, and so we know the structs match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exact layout tests are generated by upstream, but they're now disconnected from upstream.
If we upgrade used upstream version, the values hardcoded here (generated with previous upstream version) might be stale.
If these tests would instead compare local structs against imported/upstream structs, the code here would not get stale and would work correctly for any upstream version.
assert_eq!(align_of::<T>(), align_of::<U>()); | ||
assert_eq!(size_of::<T>(), size_of::<U>()); | ||
// Safe because `src` is aligned, the two types have the same size and alignment, | ||
// and they are both plain old data structs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to guarantee this? Maybe force them through a dummy FFI or something similar to make sure we don't accidentally break this assumption?
My worry is that the function safety is based on only using it for POD or repr(C)
data, but that isn't in any way enforced, and we could accidentally misuse it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assumption must hold for kvm bindings, and the unit tests and sanity checks above verify everything except the presence of #[repr(C)]
, which is where the dummy FFI might come in handy for extra certainty.
// macro (i.e. `use kvm_bindings as upstream;`). It also requires the `convert_bitwise` | ||
// function above to be in scope. | ||
#[macro_export] | ||
macro_rules! impl_conversions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool how conversion is ultimately only casting and thus no/low overhead 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this is not just casting, but rather equivalent to a memcpy
. My initial measurements didn't detect significant overhead, so maybe it's the compiler that in the end applies some more simplifications.
|
||
/// Helper function for FamStructWrapper conversion. Can/should be replaced by implementing | ||
/// `From` for `FamStructWrapper` in `vmm-sys-util`. | ||
pub fn convert_fam_struct_wrapper<'a, T, U>(src: &'a FamStructWrapper<T>) -> FamStructWrapper<U> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is reallocation with deep copy, is there any way to do some trickery here as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extent of the copying is comparable to the conversion above, but it can be made to look simpler :D
How does the versioning-by-proxy work when adding a new field to one of the versioned structs? I think an example for that would be very useful in getting a complete picture of how the proxy approach works. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking and the comments everyone! Gerry, can you share more details about the trap you mention? Sounds like an interesting situation. Regarding the example, I don't have anything at hand but it should be exactly the same as for the other approach; what's different here is where the Versionize
-aware definitions are kept.
use super::*; | ||
|
||
#[test] | ||
fn bindgen_test_layout_kvm_pic_state() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, what wasn't clearly presented is the layout tests are actually the ones generated for the upstream bindings, and so we know the structs match.
assert_eq!(align_of::<T>(), align_of::<U>()); | ||
assert_eq!(size_of::<T>(), size_of::<U>()); | ||
// Safe because `src` is aligned, the two types have the same size and alignment, | ||
// and they are both plain old data structs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The assumption must hold for kvm bindings, and the unit tests and sanity checks above verify everything except the presence of #[repr(C)]
, which is where the dummy FFI might come in handy for extra certainty.
// macro (i.e. `use kvm_bindings as upstream;`). It also requires the `convert_bitwise` | ||
// function above to be in scope. | ||
#[macro_export] | ||
macro_rules! impl_conversions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this is not just casting, but rather equivalent to a memcpy
. My initial measurements didn't detect significant overhead, so maybe it's the compiler that in the end applies some more simplifications.
|
||
/// Helper function for FamStructWrapper conversion. Can/should be replaced by implementing | ||
/// `From` for `FamStructWrapper` in `vmm-sys-util`. | ||
pub fn convert_fam_struct_wrapper<'a, T, U>(src: &'a FamStructWrapper<T>) -> FamStructWrapper<U> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extent of the copying is comparable to the conversion above, but it can be made to look simpler :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the example, I don't have anything at hand but it should be exactly the same as for the other approach; what's different here is where the Versionize-aware definitions are kept.
In theory it should work the same, but I'm having a hard time getting my head wrapped around those conversions when we have multiple versions/layouts of a struct.
The mechanisms here are quite complex and adding a practical example would greatly help understanding things better.
use super::*; | ||
|
||
#[test] | ||
fn bindgen_test_layout_kvm_pic_state() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exact layout tests are generated by upstream, but they're now disconnected from upstream.
If we upgrade used upstream version, the values hardcoded here (generated with previous upstream version) might be stale.
If these tests would instead compare local structs against imported/upstream structs, the code here would not get stale and would work correctly for any upstream version.
Hmm, can't reply to the individual comments for some reason. Yeah, the staleness aspect is supposed to be addressed when changing the upstream version, and it wasn't captured here. One way of doing it that's aligned with your proposal is to An example is definitely useful, but until one will be available just wanted to clarify the similarity aspect a bit. In both approaches there is are structs annotated with |
No description provided.