/* -*- c++ -*- */ /* * Copyright 2020 Free Software Foundation, Inc. * * This file is part of GNU Radio * * SPDX-License-Identifier: GPL-3.0-or-later * */ #ifndef INCLUDED_GR_RUNTIME_BUFFER_SINGLE_MAPPED_H #define INCLUDED_GR_RUNTIME_BUFFER_SINGLE_MAPPED_H #include <cstddef> #include <functional> #include <gnuradio/api.h> #include <gnuradio/buffer.h> #include <gnuradio/buffer_reader.h> #include <gnuradio/logger.h> #include <gnuradio/runtime_types.h> namespace gr { /*! * \brief A single mapped buffer where wrapping conditions are handled explicitly * via input/output_blocked_callback functions called from block_executor. * \ingroup internal */ class GR_RUNTIME_API buffer_single_mapped : public buffer { public: gr::logger_ptr d_logger; gr::logger_ptr d_debug_logger; ~buffer_single_mapped() override; /*! * \brief Return the block that owns this buffer. */ block_sptr buf_owner() { return d_buf_owner; } /*! * \brief return number of items worth of space available for writing */ int space_available() override; void update_reader_block_history(unsigned history, int delay) override; /*! * \brief Return true if thread is ready to call input_blocked_callback, * false otherwise */ bool input_blkd_cb_ready(int items_required, unsigned read_index) override; /*! * \brief Callback function that the scheduler will call when it determines * that the input is blocked. Override this function if needed. */ bool input_blocked_callback(int items_required, int items_avail, unsigned read_index) override = 0; /*! * \brief Return true if thread is ready to call the callback, false otherwise */ bool output_blkd_cb_ready(int output_multiple) override; /*! * \brief Callback function that the scheduler will call when it determines * that the output is blocked */ bool output_blocked_callback(int output_multiple, bool force) override = 0; protected: /*! * \brief Make reasonable attempt to adjust nitems based on read/write * granularity then delegate actual allocation to do_allocate_buffer(). * @return true iff successful. */ bool allocate_buffer(int nitems) override; /*! * \brief Do actual buffer allocation. This is intended (required) to be * handled by the derived class. */ virtual bool do_allocate_buffer(size_t final_nitems, size_t sizeof_item) = 0; unsigned index_add(unsigned a, unsigned b) override { unsigned s = a + b; if (s >= d_bufsize) s -= d_bufsize; assert(s < d_bufsize); return s; } unsigned index_sub(unsigned a, unsigned b) override { // NOTE: a is writer ptr and b is read ptr int s = a - b; if (s < 0) s = d_bufsize - b; assert((unsigned)s < d_bufsize); return s; } friend class buffer_reader; friend GR_RUNTIME_API buffer_sptr make_buffer(int nitems, size_t sizeof_item, uint64_t downstream_lcm_nitems, block_sptr link, block_sptr buf_owner); block_sptr d_buf_owner; // block that "owns" this buffer std::unique_ptr<char[]> d_buffer; /*! * \brief constructor is private. Use gr_make_buffer to create instances. * * Allocate a buffer that holds at least \p nitems of size \p sizeof_item. * * \param nitems is the minimum number of items the buffer will hold. * \param sizeof_item is the size of an item in bytes. * \param downstream_lcm_nitems is the least common multiple of the items to * read by downstream blocks * \param downstream_max_out_mult is the maximum output multiple of all * downstream blocks * \param link is the block that writes to this buffer. * \param buf_owner if the block that owns the buffer which may or may not * be the same as the block that writes to this buffer * * The total size of the buffer will be rounded up to a system * dependent boundary. This is typically the system page size, but * under MS windows is 64KB. */ buffer_single_mapped(int nitems, size_t sizeof_item, uint64_t downstream_lcm_nitems, uint32_t downstream_max_out_mult, block_sptr link, block_sptr buf_owner); /*! * \brief Abstracted logic for the input blocked callback function. * * This function contains the logic for the input blocked callback however * the data adjustment portion of the callback has been abstracted to allow * the caller to pass in the desired buffer and corresponding buffer * manipulation functions (memcpy and memmove). * * The input blocked callback is called when a reader needs to read more * data than is available in a buffer and the available data is located at * the end of the buffer. The input blocked callback will attempt to move * any data located at the beginning of the buffer "down", and will then * attempt to copy from the end of the buffer back to the beginning of the * buffer. This process explicitly handles wrapping for a single mapped * buffer and will realign the data at the beginning of the buffer such * that the reader is able to read the available data and becomes unblocked. * * \param items_required is the number of items required by the reader * \param items_avail is the number of items available * \param read_index is the current read index of the buffer reader caller * \param buffer_ptr is the pointer to the desired buffer * \param memcpy_func is a pointer to a memcpy function appropriate for the * the passed in buffer * \param memmove_func is a pointer to a memmove function appropriate for * the passed in buffer */ virtual bool input_blocked_callback_logic(int items_required, int items_avail, unsigned read_index, char* buffer_ptr, mem_func_t const& memcpy_func, mem_func_t const& memmove_func); /*! * \brief Abstracted logic for the output blocked callback function. * * This function contains the logic for the output blocked callback however * the data adjustment portion of the callback has been abstracted to allow * the caller to pass in the desired buffer and corresponding buffer * manipulation functions (memcpy and memmove). * * The output blocked callback is called when a block needs to write data * to the end of a single mapped buffer but not enough free space exists to * write the data before the end of the buffer is reached. The output blocked * callback will attempt to copy data located towards the end of a single * mapped buffer back to the beginning of the buffer. This process explicitly * handles wrapping for a single mapped buffer and will realign data located * at the end of a buffer back to the beginning of the buffer such that the * writing block can write its output into the buffer after the existing data. * * \param output_multiple * \param force run the callback disregarding the internal checks * \param buffer_ptr is the pointer to the desired buffer * \param memmove_func is a pointer to a memmove function appropriate for * the passed in buffer */ virtual bool output_blocked_callback_logic(int output_multiple, bool force, char* buffer_ptr, mem_func_t const& memmove_func); }; } /* namespace gr */ #endif /* INCLUDED_GR_RUNTIME_BUFFER_SINGLE_MAPPED_H */