Skip to content

Commit 13ed2a6

Browse files
committed
use field offset to handle field level align attribute
1 parent 896e47a commit 13ed2a6

File tree

5 files changed

+175
-40
lines changed

5 files changed

+175
-40
lines changed

src/codegen/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,11 @@ impl CodeGenerator for CompInfo {
11131113
}
11141114
};
11151115

1116+
if let Some(padding_field) =
1117+
struct_layout.pad_field(&field_name, field_ty, field.offset()) {
1118+
fields.push(padding_field);
1119+
}
1120+
11161121
let is_private = field.annotations()
11171122
.private_fields()
11181123
.unwrap_or(fields_should_be_private);
@@ -1130,10 +1135,6 @@ impl CodeGenerator for CompInfo {
11301135
let field = field.with_attrs(attrs)
11311136
.build_ty(ty.clone());
11321137

1133-
if let Some(padding_field) = struct_layout.pad_field(field_ty) {
1134-
fields.push(padding_field);
1135-
}
1136-
11371138
fields.push(field);
11381139

11391140
// TODO: Factor the following code out, please!

src/codegen/struct_layout.rs

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -68,41 +68,56 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
6868
self.max_field_align = cmp::max(self.max_field_align, layout.align);
6969
}
7070

71-
pub fn pad_field(&mut self, field_ty: &Type) -> Option<ast::StructField> {
71+
pub fn pad_field(&mut self,
72+
field_name: &str,
73+
field_ty: &Type,
74+
field_offset: Option<usize>)
75+
-> Option<ast::StructField> {
7276
field_ty.layout(self.ctx).and_then(|field_layout| {
7377
self.align_to_latest_field();
7478

75-
let calculated_layout = field_ty.as_comp()
76-
.and_then(|comp| comp.calc_layout(self.ctx))
77-
.unwrap_or(field_layout);
78-
79-
let padding_bytes = if self.comp.packed() {
80-
0
81-
} else {
82-
self.padding_bytes(field_layout)
83-
};
84-
let align = if self.comp.packed() {
85-
mem::size_of::<u8>()
79+
let padding_layout = if self.comp.packed() {
80+
None
8681
} else {
87-
cmp::min(calculated_layout.align, mem::size_of::<*mut ()>())
82+
let calculated_layout = field_ty.as_comp()
83+
.and_then(|comp| comp.calc_layout(self.ctx))
84+
.unwrap_or(field_layout);
85+
86+
let align = cmp::min(calculated_layout.align, mem::size_of::<*mut ()>());
87+
88+
let (padding_bytes, need_padding) = match field_offset {
89+
Some(offset) if offset / 8 > self.latest_offset => {
90+
(offset / 8 - self.latest_offset, true)
91+
}
92+
_ => {
93+
(self.padding_bytes(field_layout), (self.latest_offset % field_layout.align) != 0)
94+
}
95+
};
96+
97+
debug!("align field {} to {}/{} with {} padding bytes {:?}, calculated {:?}",
98+
field_name,
99+
self.latest_offset + padding_bytes,
100+
field_offset.unwrap_or(0) / 8,
101+
padding_bytes,
102+
field_layout,
103+
calculated_layout);
104+
105+
if need_padding &&
106+
(padding_bytes > calculated_layout.align ||
107+
field_layout.align > mem::size_of::<*mut ()>()) {
108+
Some(Layout::new(padding_bytes, align))
109+
} else {
110+
None
111+
}
88112
};
89113

90-
let need_padding = (self.latest_offset % field_layout.align) != 0 &&
91-
(padding_bytes > calculated_layout.align ||
92-
field_layout.align > mem::size_of::<*mut ()>());
114+
self.latest_offset += padding_layout.map(|layout| layout.size).unwrap_or(0) +
115+
field_ty.calc_size(self.ctx).unwrap_or(field_layout.size);
93116

94-
self.latest_offset += padding_bytes +
95-
field_ty.calc_size(self.ctx)
96-
.unwrap_or(field_layout.size);
97117
self.latest_field_layout = Some(field_layout);
98-
self.max_field_align = cmp::max(self.max_field_align,
99-
field_layout.align);
118+
self.max_field_align = cmp::max(self.max_field_align, field_layout.align);
100119

101-
if need_padding {
102-
Some(self.padding_field(Layout::new(padding_bytes, align)))
103-
} else {
104-
None
105-
}
120+
padding_layout.map(|layout| self.padding_field(layout))
106121
})
107122
}
108123

@@ -114,16 +129,19 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
114129
None
115130
} else {
116131
let padding_bytes = layout.size - self.latest_offset;
132+
let struct_align = cmp::min(layout.align,
133+
mem::size_of::<*mut ()>());
117134

118-
let align = if self.comp.packed() {
119-
mem::size_of::<u8>()
120-
} else {
121-
cmp::min(layout.align, mem::size_of::<*mut ()>())
122-
};
123-
124-
if padding_bytes >= align ||
135+
if padding_bytes > struct_align ||
125136
(layout.align > mem::size_of::<*mut ()>() && padding_bytes > 0) {
126-
Some(self.padding_field(Layout::new(padding_bytes, align)))
137+
let padding_align = if self.comp.packed() {
138+
1
139+
} else {
140+
cmp::min(1 << padding_bytes.trailing_zeros(),
141+
mem::size_of::<*mut ()>())
142+
};
143+
144+
Some(self.padding_field(Layout::new(padding_bytes, padding_align)))
127145
} else {
128146
None
129147
}
@@ -165,7 +183,9 @@ impl<'a, 'ctx> StructLayoutTracker<'a, 'ctx> {
165183
}
166184

167185
fn align_to_latest_field(&mut self) {
168-
if let Some(layout) = self.latest_field_layout {
186+
if self.comp.packed() {
187+
// skip to align field when packed
188+
} else if let Some(layout) = self.latest_field_layout {
169189
self.latest_offset += self.padding_bytes(layout);
170190
}
171191
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const RTE_CACHE_LINE_MIN_SIZE: ::std::os::raw::c_uint = 64;
8+
pub const RTE_CACHE_LINE_SIZE: ::std::os::raw::c_uint = 64;
9+
#[repr(C)]
10+
#[derive(Debug, Copy)]
11+
pub struct rte_kni_mbuf {
12+
pub buf_addr: *mut ::std::os::raw::c_void,
13+
pub buf_physaddr: u64,
14+
pub pad0: [::std::os::raw::c_char; 2usize],
15+
/**< Start address of data in segment buffer. */
16+
pub data_off: u16,
17+
pub pad1: [::std::os::raw::c_char; 2usize],
18+
/**< Number of segments. */
19+
pub nb_segs: u8,
20+
pub pad4: [::std::os::raw::c_char; 1usize],
21+
/**< Offload features. */
22+
pub ol_flags: u64,
23+
pub pad2: [::std::os::raw::c_char; 4usize],
24+
/**< Total pkt len: sum of all segment data_len. */
25+
pub pkt_len: u32,
26+
/**< Amount of data in segment buffer. */
27+
pub data_len: u16,
28+
pub __bindgen_padding_0: [u8; 22usize],
29+
pub pad3: [::std::os::raw::c_char; 8usize],
30+
pub pool: *mut ::std::os::raw::c_void,
31+
pub next: *mut ::std::os::raw::c_void,
32+
pub __bindgen_padding_1: [u64; 5usize],
33+
}
34+
#[test]
35+
fn bindgen_test_layout_rte_kni_mbuf() {
36+
assert_eq!(::std::mem::size_of::<rte_kni_mbuf>() , 128usize);
37+
assert_eq! (unsafe {
38+
& ( * ( 0 as * const rte_kni_mbuf ) ) . buf_addr as * const _
39+
as usize } , 0usize);
40+
assert_eq! (unsafe {
41+
& ( * ( 0 as * const rte_kni_mbuf ) ) . buf_physaddr as *
42+
const _ as usize } , 8usize);
43+
assert_eq! (unsafe {
44+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pad0 as * const _ as
45+
usize } , 16usize);
46+
assert_eq! (unsafe {
47+
& ( * ( 0 as * const rte_kni_mbuf ) ) . data_off as * const _
48+
as usize } , 18usize);
49+
assert_eq! (unsafe {
50+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pad1 as * const _ as
51+
usize } , 20usize);
52+
assert_eq! (unsafe {
53+
& ( * ( 0 as * const rte_kni_mbuf ) ) . nb_segs as * const _
54+
as usize } , 22usize);
55+
assert_eq! (unsafe {
56+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pad4 as * const _ as
57+
usize } , 23usize);
58+
assert_eq! (unsafe {
59+
& ( * ( 0 as * const rte_kni_mbuf ) ) . ol_flags as * const _
60+
as usize } , 24usize);
61+
assert_eq! (unsafe {
62+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pad2 as * const _ as
63+
usize } , 32usize);
64+
assert_eq! (unsafe {
65+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pkt_len as * const _
66+
as usize } , 36usize);
67+
assert_eq! (unsafe {
68+
& ( * ( 0 as * const rte_kni_mbuf ) ) . data_len as * const _
69+
as usize } , 40usize);
70+
assert_eq! (unsafe {
71+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pad3 as * const _ as
72+
usize } , 64usize);
73+
assert_eq! (unsafe {
74+
& ( * ( 0 as * const rte_kni_mbuf ) ) . pool as * const _ as
75+
usize } , 72usize);
76+
assert_eq! (unsafe {
77+
& ( * ( 0 as * const rte_kni_mbuf ) ) . next as * const _ as
78+
usize } , 80usize);
79+
}
80+
impl Clone for rte_kni_mbuf {
81+
fn clone(&self) -> Self { *self }
82+
}

tests/expectations/tests/layout_mbuf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub struct rte_mbuf {
103103
pub priv_size: u16,
104104
/** Timesync flags for use with IEEE1588. */
105105
pub timesync: u16,
106-
pub __bindgen_padding_0: [u64; 3usize],
106+
pub __bindgen_padding_0: [u32; 7usize],
107107
}
108108
/**
109109
* 16-bit Reference counter.

tests/headers/layout_kni_mbuf.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
#define RTE_CACHE_LINE_MIN_SIZE 64 /**< Minimum Cache line size. */
3+
4+
#define RTE_CACHE_LINE_SIZE 64
5+
6+
typedef unsigned char uint8_t;
7+
typedef unsigned short uint16_t;
8+
typedef unsigned int uint32_t;
9+
typedef unsigned long long uint64_t;
10+
11+
/*
12+
* The kernel image of the rte_mbuf struct, with only the relevant fields.
13+
* Padding is necessary to assure the offsets of these fields
14+
*/
15+
struct rte_kni_mbuf {
16+
void *buf_addr __attribute__((__aligned__(RTE_CACHE_LINE_SIZE)));
17+
uint64_t buf_physaddr;
18+
char pad0[2];
19+
uint16_t data_off; /**< Start address of data in segment buffer. */
20+
char pad1[2];
21+
uint8_t nb_segs; /**< Number of segments. */
22+
char pad4[1];
23+
uint64_t ol_flags; /**< Offload features. */
24+
char pad2[4];
25+
uint32_t pkt_len; /**< Total pkt len: sum of all segment data_len. */
26+
uint16_t data_len; /**< Amount of data in segment buffer. */
27+
28+
/* fields on second cache line */
29+
char pad3[8] __attribute__((__aligned__(RTE_CACHE_LINE_MIN_SIZE)));
30+
void *pool;
31+
void *next;
32+
};

0 commit comments

Comments
 (0)