diff --git a/src/maps/bpf_perf_buffer.h b/src/maps/bpf_perf_buffer.h deleted file mode 100644 index d0ee10d..0000000 --- a/src/maps/bpf_perf_buffer.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef PYLIBBPF_PERF_EVENT_ARRAY_H -#define PYLIBBPF_PERF_EVENT_ARRAY_H - -#include -#include -#include -#include - -class StructParser; - -namespace py = pybind11; - -class PerfEventArray { -private: - struct perf_buffer *pb_; - py::function callback_; - py::function lost_callback_; - - std::shared_ptr parser_; - std::string struct_name_; - - // Static callback wrappers for C API - static void sample_callback_wrapper(void *ctx, int cpu, void *data, - unsigned int size); - static void lost_callback_wrapper(void *ctx, int cpu, unsigned long long cnt); - -public: - PerfEventArray(int map_fd, int page_cnt, py::function callback, - py::object lost_callback = py::none()); - ~PerfEventArray(); - - int poll(int timeout_ms); - int consume(); - [[nodiscard]] int fd() const; -}; - -#endif // PYLIBBPF_PERF_EVENT_ARRAY_H diff --git a/src/maps/perf_event_array.cpp b/src/maps/perf_event_array.cpp index 7d53e9d..a8183b8 100644 --- a/src/maps/perf_event_array.cpp +++ b/src/maps/perf_event_array.cpp @@ -1,11 +1,17 @@ #include "perf_event_array.h" #include "core/bpf_exception.h" +#include "core/bpf_map.h" -PerfEventArray::PerfEventArray(int map_fd, int page_cnt, py::function callback, - py::object lost_callback) - : pb_(nullptr), callback_(std::move(callback)), +PerfEventArray::PerfEventArray(std::shared_ptr map, int page_cnt, + py::function callback, py::object lost_callback) + : map_(map), pb_(nullptr), callback_(std::move(callback)), lost_callback_(lost_callback) { + if (map->get_type() != BPF_MAP_TYPE_PERF_EVENT_ARRAY) { + throw BpfException("Map '" + map->get_name() + + "' is not a PERF_EVENT_ARRAY"); + } + if (page_cnt <= 0 || (page_cnt & (page_cnt - 1)) != 0) { throw BpfException("page_cnt must be a positive power of 2"); } @@ -14,7 +20,7 @@ PerfEventArray::PerfEventArray(int map_fd, int page_cnt, py::function callback, pb_opts.sz = sizeof(pb_opts); // Required for forward compatibility pb_ = perf_buffer__new( - map_fd, page_cnt, + map->get_fd(), page_cnt, sample_callback_wrapper, // sample_cb lost_callback.is_none() ? nullptr : lost_callback_wrapper, // lost_cb this, // ctx @@ -27,6 +33,25 @@ PerfEventArray::PerfEventArray(int map_fd, int page_cnt, py::function callback, } } +PerfEventArray::PerfEventArray(std::shared_ptr map, int page_cnt, + py::function callback, + const std::string &struct_name, + py::object lost_callback) + : PerfEventArray(map, page_cnt, callback, lost_callback) { + + auto parent = map->get_parent(); + if (!parent) { + throw BpfException("Parent BpfObject has been destroyed"); + } + + parser_ = parent->get_struct_parser(); + struct_name_ = struct_name; + + if (!parser_) { + throw BpfException("No struct definitions available"); + } +} + PerfEventArray::~PerfEventArray() { if (pb_) { perf_buffer__free(pb_); @@ -34,7 +59,7 @@ PerfEventArray::~PerfEventArray() { } void PerfEventArray::sample_callback_wrapper(void *ctx, int cpu, void *data, - unsigned int size) { + unsigned int size) { auto *self = static_cast(ctx); // Acquire GIL for Python calls @@ -44,15 +69,23 @@ void PerfEventArray::sample_callback_wrapper(void *ctx, int cpu, void *data, // Convert data to Python bytes py::bytes py_data(static_cast(data), size); - // Call Python callback: callback(cpu, data, size) - self->callback_(cpu, py_data, size); + if (self->parser_ && !self->struct_name_.empty()) { + py::object event = self->parser_->parse(self->struct_name_, py_data); + self->callback_(cpu, event); + } else { + self->callback_(cpu, py_data); + } + } catch (const py::error_already_set &e) { PyErr_Print(); + } catch (const std::exception &e) { + py::gil_scoped_acquire acquire; + py::print("C++ error in perf callback:", e.what()); } } void PerfEventArray::lost_callback_wrapper(void *ctx, int cpu, - unsigned long long cnt) { + unsigned long long cnt) { auto *self = static_cast(ctx); if (self->lost_callback_.is_none()) { diff --git a/src/maps/perf_event_array.h b/src/maps/perf_event_array.h index 86a2c83..0d09210 100644 --- a/src/maps/perf_event_array.h +++ b/src/maps/perf_event_array.h @@ -1,5 +1,5 @@ -#ifndef PYLIBBPF_BPF_PERF_BUFFER_H -#define PYLIBBPF_BPF_PERF_BUFFER_H +#ifndef PYLIBBPF_PERF_EVENT_ARRAY_H +#define PYLIBBPF_PERF_EVENT_ARRAY_H #include #include @@ -7,11 +7,13 @@ #include class StructParser; +class BpfMap; namespace py = pybind11; class PerfEventArray { private: + std::shared_ptr map_; struct perf_buffer *pb_; py::function callback_; py::function lost_callback_; @@ -25,13 +27,20 @@ private: static void lost_callback_wrapper(void *ctx, int cpu, unsigned long long cnt); public: - PerfEventArray(int map_fd, int page_cnt, py::function callback, - py::object lost_callback = py::none()); + PerfEventArray(std::shared_ptr map, int page_cnt, + py::function callback, py::object lost_callback = py::none()); + PerfEventArray(std::shared_ptr map, int page_cnt, + py::function callback, const std::string &struct_name, + py::object lost_callback = py::none()); ~PerfEventArray(); + PerfEventArray(const PerfEventArray &) = delete; + PerfEventArray &operator=(const PerfEventArray &) = delete; + int poll(int timeout_ms); int consume(); - [[nodiscard]] int fd() const; + + [[nodiscard]] std::shared_ptr get_map() const { return map_; } }; -#endif // PYLIBBPF_BPF_PERF_BUFFER_H +#endif // PYLIBBPF_PERF_EVENT_ARRAY_H