libbpf-rs icon indicating copy to clipboard operation
libbpf-rs copied to clipboard

`*mut perf_buffer` cannot be sent between threads safely within `PerfBuffer<'_>`

Open chengshuyi opened this issue 3 years ago • 3 comments

I want to create a thread to receive perf data and pass the data to the main thread for processing through crossbeam_channel. But there was trouble.

below is my code.

thread::spawn(move || loop {
        perf.poll(Duration::from_millis(100)).unwrap();
    });

below is the error message.

`dyn libbpf_rs::perf_buffer::SampleCb<for<'r> Output = ()>` cannot be sent between threads safely
the trait `Send` is not implemented for `dyn libbpf_rs::perf_buffer::SampleCb<for<'r> Output = ()>`
required because of the requirements on the impl of `Send` for `Unique<dyn libbpf_rs::perf_buffer::SampleCb<for<'r> Output = ()>>`
required because of the requirements on the impl of `Send` for `Unique<libbpf_rs::perf_buffer::CbStruct<'_>>`
required because of the requirements on the impl of `Send` for `Mutex<PerfBuffer<'_>>`
required because it appears within the type `[closure@src/main.rs:72:19: 74:6]`rustc[E0277](https://doc.rust-lang.org/error-index.html#E0277)

Maybe we can add this line of code to solve the problem, what do you think?

unsafe impl Send for PerfBuffer {}

Thanks in advance!

chengshuyi avatar May 06 '22 08:05 chengshuyi

I don't think perf buffers can be transferred across thread boundaries because internally the perfbuffer's circular buffers are per-CPU, and there is no guarantee that the two threads will run on the same CPU (please correct me if I'm wrong here though @anakryiko). I don't think we can PerfBuffer can have the Send trait.

Ringbuffers though can be safely shared across multiple CPUs simultaneously. Maybe the ringbuffer would solve your use case instead of the perfbuffer? https://nakryiko.com/posts/bpf-ringbuf/ is a great article explaining the differences between the ringbuf and perfbuf.

insearchoflosttime avatar May 06 '22 17:05 insearchoflosttime

Both ringbuf and perfbuf can poll from any thread, as long as it's a single thread. So it should be possible to Send them to another thread. As long as Send implies a move, and not sharing? I'm forgetting exact semantics for Send, but there is no problem in polling for updates from any thread.

anakryiko avatar May 06 '22 20:05 anakryiko

Ah okay, I think I'm confusing how perfbuffers work internally then. I'll take another look at the libbpf implementation. thanks for clarifying

insearchoflosttime avatar May 06 '22 20:05 insearchoflosttime