1use std::time::Duration;
2use super::{skeleton::MapRef, kind};
3
4pub struct RingBufferRef(MapRef);
5
6impl kind::AppItem for RingBufferRef {
7 const MAP: usize = 1;
8 const PROG: usize = 0;
9
10 fn named(name: &'static str) -> Self {
11 RingBufferRef(MapRef::named(name))
12 }
13
14 fn kind_mut(&mut self) -> kind::AppItemKindMut<'_> {
15 kind::AppItemKindMut::Map(&mut self.0)
16 }
17}
18
19pub struct RingBufferRegistry {
20 inner: *mut libbpf_sys::ring_buffer,
21 callbacks: Vec<Box<dyn FnMut(&[u8])>>,
22}
23
24impl Default for RingBufferRegistry {
25 fn default() -> Self {
26 use std::ptr;
27
28 RingBufferRegistry {
29 inner: ptr::null_mut(),
30 callbacks: Vec::with_capacity(256),
31 }
32 }
33}
34
35impl Drop for RingBufferRegistry {
36 fn drop(&mut self) {
37 if !self.inner.is_null() {
38 unsafe { libbpf_sys::ring_buffer__free(self.inner) };
39 }
40 }
41}
42
43impl RingBufferRegistry {
44 unsafe extern "C" fn cb(ctx: *mut cty::c_void, data: *mut cty::c_void, size: u64) -> i32 {
45 use std::slice;
46
47 let ctx = ctx as *mut Box<dyn FnMut(&[u8]) + 'static>;
48 let s = slice::from_raw_parts(data as *mut u8 as *const u8, size as _);
49 (*ctx)(s);
50 0
51 }
52
53 pub fn add<F>(&mut self, rb: &RingBufferRef, cb: F) -> Result<(), i32>
54 where
55 F: for<'r> FnMut(&'r [u8]) + 'static,
56 {
57 self.add_fd(rb.0.fd(), cb)
58 }
59
60 pub fn add_fd<F>(&mut self, map_fd: i32, cb: F) -> Result<(), i32>
61 where
62 F: for<'r> FnMut(&'r [u8]) + 'static,
63 {
64 use std::ptr;
65
66 let cb: Box<dyn FnMut(&[u8]) + 'static> = Box::new(cb);
67 self.callbacks.push(cb);
68 let ctx = self.callbacks.last_mut().unwrap() as *mut _;
69 if self.inner.is_null() {
70 self.inner = unsafe {
71 libbpf_sys::ring_buffer__new(map_fd, Some(Self::cb), ctx as _, ptr::null_mut())
72 };
73 Ok(())
74 } else {
75 let c = unsafe {
76 libbpf_sys::ring_buffer__add(self.inner, map_fd, Some(Self::cb), ctx as _)
77 };
78 if c != 0 {
79 Err(c)
80 } else {
81 Ok(())
82 }
83 }
84 }
85
86 pub fn poll(&self, timeout: Duration) -> Result<usize, i32> {
87 if self.inner.is_null() {
88 return Ok(0);
89 }
90
91 let c = unsafe { libbpf_sys::ring_buffer__poll(self.inner, timeout.as_millis() as i32) };
92
93 if c < 0 {
94 Err(c)
95 } else {
96 Ok(c as _)
97 }
98 }
99
100 pub fn consume(&self) -> Result<usize, i32> {
101 if self.inner.is_null() {
102 return Ok(0);
103 }
104
105 let c = unsafe { libbpf_sys::ring_buffer__consume(self.inner) };
106
107 if c < 0 {
108 Err(c)
109 } else {
110 Ok(c as _)
111 }
112 }
113
114 pub fn epoll_fd(&self) -> Option<i32> {
115 if self.inner.is_null() {
116 None
117 } else {
118 Some(unsafe { libbpf_sys::ring_buffer__epoll_fd(self.inner) })
119 }
120 }
121}