1
1
use crate :: * ;
2
+ use std:: io:: { self , Write } ;
2
3
use std:: os:: raw:: c_char;
3
4
use std:: sync:: atomic:: { AtomicPtr , Ordering } ;
4
5
@@ -24,8 +25,29 @@ impl From<libbpf_sys::libbpf_print_level> for PrintLevel {
24
25
25
26
pub type PrintCallback = fn ( PrintLevel , & str ) ;
26
27
28
+ /// Mimic the default print functionality of libbpf. This way if the user calls `set_print` when no
29
+ /// previous callback had been set and then tries to restore it, it will appear to work correctly.
30
+ fn default_callback ( lvl : PrintLevel , msg : & str ) {
31
+ if lvl == PrintLevel :: Debug {
32
+ return ;
33
+ }
34
+
35
+ let _ = io:: stderr ( ) . write ( msg. as_bytes ( ) ) ;
36
+ }
37
+
38
+ // not allowed to use function pointers in const functions, so it needs to be a macro
39
+ macro_rules! to_ptr {
40
+ ( $x: expr) => {
41
+ unsafe { std:: mem:: transmute:: <PrintCallback , * mut ( ) >( $x) }
42
+ } ;
43
+ }
44
+
45
+ fn from_ptr ( ptr : * mut ( ) ) -> PrintCallback {
46
+ unsafe { std:: mem:: transmute :: < * mut ( ) , PrintCallback > ( ptr) }
47
+ }
48
+
27
49
// There is no AtomicFnPtr. This is a workaround.
28
- static PRINT_CB : AtomicPtr < ( ) > = AtomicPtr :: new ( std :: ptr :: null_mut ( ) ) ;
50
+ static PRINT_CB : AtomicPtr < ( ) > = AtomicPtr :: new ( to_ptr ! ( default_callback ) ) ;
29
51
30
52
/// libbpf's default cb uses vfprintf's return code...which is ignored everywhere. Mimic that for
31
53
/// completeness
@@ -34,27 +56,33 @@ extern "C" fn outer_print_cb(
34
56
fmtstr : * const c_char ,
35
57
va_list : * mut libbpf_sys:: __va_list_tag ,
36
58
) -> i32 {
37
- // can't be null: we cant't get here until print_cb has been initialized with a function
38
- // pointer.
39
- let cb = PRINT_CB . load ( Ordering :: Relaxed ) ;
40
- let cb = unsafe { std:: mem:: transmute :: < * const ( ) , PrintCallback > ( cb) } ;
59
+ let cb = from_ptr ( PRINT_CB . load ( Ordering :: Relaxed ) ) ;
41
60
match unsafe { vsprintf:: vsprintf ( fmtstr, va_list) } {
42
61
Ok ( s) => {
43
62
cb ( level. into ( ) , & s) ;
44
63
s. len ( ) as i32
45
64
}
46
- Err ( _) => {
47
- cb ( PrintLevel :: Warn , "Could not format libbpf log string" ) ;
65
+ Err ( e) => {
66
+ cb (
67
+ PrintLevel :: Warn ,
68
+ & format ! ( "Failed to parse libbpf output: {}" , e) ,
69
+ ) ;
48
70
-1
49
71
}
50
72
}
51
73
}
52
74
53
- /// Set a callback to receive log messages from libbpf, instead of printing them to stderr
75
+ /// Set a callback to receive log messages from libbpf, instead of printing them to stderr. Returns
76
+ /// the previous callback.
77
+ ///
78
+ /// # Arguments
79
+ ///
80
+ /// * `func` - The callback
54
81
///
55
82
/// This overrides (and is overridden by) [`ObjectBuilder::debug`]
56
- pub fn set_print ( func : PrintCallback ) {
57
- let cb = unsafe { std :: mem :: transmute :: < PrintCallback , * mut ( ) > ( func) } ;
58
- PRINT_CB . store ( cb, Ordering :: Relaxed ) ;
83
+ pub fn set_print ( func : PrintCallback ) -> PrintCallback {
84
+ let cb = to_ptr ! ( func) ;
85
+ let prev = PRINT_CB . swap ( cb, Ordering :: Relaxed ) ;
59
86
unsafe { libbpf_sys:: libbpf_set_print ( Some ( outer_print_cb) ) } ;
87
+ from_ptr ( prev)
60
88
}
0 commit comments