@ -303,6 +303,10 @@ impl ProducerData {
let len = page_size + 2 * usize ::try_from ( byte_size ) . unwrap ( ) ;
let len = page_size + 2 * usize ::try_from ( byte_size ) . unwrap ( ) ;
let mmap = MMap ::new ( fd , len , PROT_READ , MAP_SHARED , offset . try_into ( ) . unwrap ( ) ) ? ;
let mmap = MMap ::new ( fd , len , PROT_READ , MAP_SHARED , offset . try_into ( ) . unwrap ( ) ) ? ;
// The producer position may be non-zero if the map is being loaded from a pin, or the map
// has been used previously; load the initial value of the producer position from the mmap.
let pos_cache = load_producer_pos ( & mmap ) ;
// byte_size is required to be a power of two multiple of page_size (which implicitly is a
// byte_size is required to be a power of two multiple of page_size (which implicitly is a
// power of 2), so subtracting one will create a bitmask for values less than byte_size.
// power of 2), so subtracting one will create a bitmask for values less than byte_size.
debug_assert! ( byte_size . is_power_of_two ( ) ) ;
debug_assert! ( byte_size . is_power_of_two ( ) ) ;
@ -310,7 +314,7 @@ impl ProducerData {
Ok ( Self {
Ok ( Self {
mmap ,
mmap ,
data_offset : page_size ,
data_offset : page_size ,
pos_cache : 0 ,
pos_cache ,
mask ,
mask ,
} )
} )
}
}
@ -322,7 +326,6 @@ impl ProducerData {
ref mut pos_cache ,
ref mut pos_cache ,
ref mut mask ,
ref mut mask ,
} = self ;
} = self ;
let pos = unsafe { mmap . ptr ( ) . cast ( ) . as_ref ( ) } ;
let mmap_data = mmap . as_ref ( ) ;
let mmap_data = mmap . as_ref ( ) ;
let data_pages = mmap_data . get ( * data_offset .. ) . unwrap_or_else ( | | {
let data_pages = mmap_data . get ( * data_offset .. ) . unwrap_or_else ( | | {
panic! (
panic! (
@ -331,7 +334,7 @@ impl ProducerData {
mmap_data . len ( )
mmap_data . len ( )
)
)
} ) ;
} ) ;
while data_available ( pos , pos_cache , consumer ) {
while data_available ( mma p, pos_cache , consumer ) {
match read_item ( data_pages , * mask , consumer ) {
match read_item ( data_pages , * mask , consumer ) {
Item ::Busy = > return None ,
Item ::Busy = > return None ,
Item ::Discard { len } = > consumer . consume ( len ) ,
Item ::Discard { len } = > consumer . consume ( len ) ,
@ -347,17 +350,15 @@ impl ProducerData {
}
}
fn data_available (
fn data_available (
producer : & AtomicUsize ,
producer : & MMap ,
cache: & mut usize ,
producer_ cache: & mut usize ,
consumer : & ConsumerPos ,
consumer : & ConsumerPos ,
) -> bool {
) -> bool {
let ConsumerPos { pos : consumer , .. } = consumer ;
let ConsumerPos { pos : consumer , .. } = consumer ;
if consumer = = cache {
// Refresh the producer position cache if it appears that the consumer is caught up
// This value is written using Release by the kernel [1], and should be read with
// with the producer position.
// Acquire to ensure that the prior writes to the entry header are visible.
if consumer = = producer_cache {
//
* producer_cache = load_producer_pos ( producer ) ;
// [1]: https://github.com/torvalds/linux/blob/eb26cbb1/kernel/bpf/ringbuf.c#L447-L448
* cache = producer . load ( Ordering ::Acquire ) ;
}
}
// Note that we don't compare the order of the values because the producer position may
// Note that we don't compare the order of the values because the producer position may
@ -369,7 +370,7 @@ impl ProducerData {
// producer position has wrapped around.
// producer position has wrapped around.
//
//
// [1]: https://github.com/torvalds/linux/blob/4b810bf0/kernel/bpf/ringbuf.c#L434-L440
// [1]: https://github.com/torvalds/linux/blob/4b810bf0/kernel/bpf/ringbuf.c#L434-L440
consumer ! = cache
consumer ! = producer_ cache
}
}
fn read_item < ' data > ( data : & ' data [ u8 ] , mask : u32 , pos : & ConsumerPos ) -> Item < ' data > {
fn read_item < ' data > ( data : & ' data [ u8 ] , mask : u32 , pos : & ConsumerPos ) -> Item < ' data > {
@ -403,3 +404,12 @@ impl ProducerData {
}
}
}
}
}
}
// Loads the producer position from the shared memory mmap.
fn load_producer_pos ( producer : & MMap ) -> usize {
// This value is written using Release by the kernel [1], and should be read with
// Acquire to ensure that the prior writes to the entry header are visible.
//
// [1]: https://github.com/torvalds/linux/blob/eb26cbb1/kernel/bpf/ringbuf.c#L447-L448
unsafe { producer . ptr ( ) . cast ::< AtomicUsize > ( ) . as_ref ( ) } . load ( Ordering ::Acquire )
}