| ===================== |
| I/O Buffer Management |
| ===================== |
| |
| NuttX supports generic I/O buffer management (IOB) logic. This |
| logic was originally added to support network I/O buffering, but |
| has been generalized to meet buffering requirements by all device |
| drivers. At the time of this writing, IOBs are currently used not |
| only be networking but also by logic in ``drivers/syslog`` and |
| ``drivers/wireless``. NOTE that some of the wording in this |
| section still reflects those legacy roots as a part of the |
| networking subsystem. This objectives of this feature are: |
| |
| #. Provide common I/O buffer management logic for all drivers, |
| #. Support I/O buffer allocation from both the tasking and |
| interrupt level contexts. |
| #. Use a fixed amount of pre-allocated memory. |
| #. No costly, non-deterministic dynamic memory allocation. |
| #. When the fixed number of pre-allocated I/O buffers is |
| exhausted, further attempts to allocate memory from tasking |
| logic will cause the task to block and wait until a an I/O |
| buffer to be freed. |
| #. Each I/O buffer should be small, but can be chained together to |
| support buffering of larger thinks such as full size network |
| packets. |
| #. Support *throttling* logic to prevent lower priority tasks from |
| hogging all available I/O buffering. |
| |
| Configuration Options |
| ===================== |
| |
| ``CONFIG_MM_IOB`` |
| Enables generic I/O buffer support. This setting will build the |
| common I/O buffer (IOB) support library. |
| ``CONFIG_IOB_NBUFFERS`` |
| Number of pre-allocated I/O buffers. Each packet is represented |
| by a series of small I/O buffers in a chain. This setting |
| determines the number of preallocated I/O buffers available for |
| packet data. The default value is setup for network support. |
| The default is 8 buffers if neither TCP/UDP or write buffering |
| is enabled (neither ``CONFIG_NET_TCP_WRITE_BUFFERS`` nor |
| ``CONFIG_NET_TCP``), 24 if only TCP/UDP is enabled, and 36 if |
| both TCP/UDP and write buffering are enabled. |
| ``CONFIG_IOB_BUFSIZE`` |
| Payload size of one I/O buffer. Each packet is represented by a |
| series of small I/O buffers in a chain. This setting determines |
| the data payload each preallocated I/O buffer. The default |
| value is 196 bytes. |
| ``CONFIG_IOB_NCHAINS`` |
| Number of pre-allocated I/O buffer chain heads. These tiny |
| nodes are used as *containers* to support queueing of I/O |
| buffer chains. This will limit the number of I/O transactions |
| that can be *in-flight* at any give time. The default value of |
| zero disables this features. |
| These generic I/O buffer chain containers are not currently |
| used by any logic in NuttX. That is because their other other |
| specialized I/O buffer chain containers that also carry a |
| payload of usage specific information. The default value is |
| zero if nether TCP nor UDP is enabled (i.e., neither |
| ``CONFIG_NET_TCP`` && !\ ``CONFIG_NET_UDP`` or eight if either |
| is enabled. |
| ``CONFIG_IOB_THROTTLE`` |
| I/O buffer throttle value. TCP write buffering and read-ahead |
| buffer use the same pool of free I/O buffers. In order to |
| prevent uncontrolled incoming TCP packets from hogging all of |
| the available, pre-allocated I/O buffers, a throttling value is |
| required. This throttle value assures that I/O buffers will be |
| denied to the read-ahead logic before TCP writes are halted. |
| The default 0 if neither TCP write buffering nor TCP read-ahead |
| buffering is enabled. Otherwise, the default is 8. |
| ``CONFIG_IOB_DEBUG`` |
| Force I/O buffer debug. This option will force debug output |
| from I/O buffer logic. This is not normally something that |
| would want to do but is convenient if you are debugging the I/O |
| buffer logic and do not want to get overloaded with other |
| un-related debug output. NOTE that this selection is not |
| available if DEBUG features are not enabled |
| (``CONFIG_DEBUG_FEATURES``) with IOBs are being used to syslog |
| buffering logic (``CONFIG_SYSLOG_BUFFER``). |
| |
| Throttling |
| ========== |
| |
| An allocation throttle was added. I/O buffer allocation logic |
| supports a throttle value originally for read-ahead buffering to |
| prevent the read-ahead logic from consuming all available I/O |
| buffers and blocking the write buffering logic. This throttle |
| logic is only needed for networking only if both write buffering |
| and read-ahead buffering are used. Of use of I/O buffering might |
| have other motivations for throttling. |
| |
| Public Types |
| ============ |
| |
| This structure represents one I/O buffer. A packet is contained by |
| one or more I/O buffers in a chain. The ``io_pktlen`` is only |
| valid for the I/O buffer at the head of the chain. |
| |
| .. code-block:: c |
| |
| struct iob_s |
| { |
| /* Singly-link list support */ |
| |
| FAR struct iob_s *io_flink; |
| |
| /* Payload */ |
| |
| #if CONFIG_IOB_BUFSIZE < 256 |
| uint8_t io_len; /* Length of the data in the entry */ |
| uint8_t io_offset; /* Data begins at this offset */ |
| #else |
| uint16_t io_len; /* Length of the data in the entry */ |
| uint16_t io_offset; /* Data begins at this offset */ |
| #endif |
| uint16_t io_pktlen; /* Total length of the packet */ |
| |
| uint8_t io_data[CONFIG_IOB_BUFSIZE]; |
| }; |
| |
| This container structure supports queuing of I/O buffer chains. |
| This structure is intended only for internal use by the IOB |
| module. |
| |
| .. code-block:: c |
| |
| #if CONFIG_IOB_NCHAINS > 0 |
| struct iob_qentry_s |
| { |
| /* Singly-link list support */ |
| |
| FAR struct iob_qentry_s *qe_flink; |
| |
| /* Payload -- Head of the I/O buffer chain */ |
| |
| FAR struct iob_s *qe_head; |
| }; |
| #endif /* CONFIG_IOB_NCHAINS > 0 */ |
| |
| The I/O buffer queue head structure. |
| |
| .. code-block:: c |
| |
| #if CONFIG_IOB_NCHAINS > 0 |
| struct iob_queue_s |
| { |
| /* Head of the I/O buffer chain list */ |
| |
| FAR struct iob_qentry_s *qh_head; |
| FAR struct iob_qentry_s *qh_tail; |
| }; |
| #endif /* CONFIG_IOB_NCHAINS > 0 */ |
| |
| Public Function Prototypes |
| ========================== |
| |
| - :c:func:`iob_initialize()` |
| - :c:func:`iob_alloc()` |
| - :c:func:`iob_tryalloc()` |
| - :c:func:`iob_free()` |
| - :c:func:`iob_free_chain()` |
| - :c:func:`iob_add_queue()` |
| - :c:func:`iob_tryadd_queue()` |
| - :c:func:`iob_remove_queue()` |
| - :c:func:`iob_peek_queue()` |
| - :c:func:`iob_free_queue()` |
| - :c:func:`iob_free_queue_qentry()` |
| - :c:func:`iob_get_queue_size()` |
| - :c:func:`iob_copyin()` |
| - :c:func:`iob_trycopyin()` |
| - :c:func:`iob_copyout()` |
| - :c:func:`iob_clone()` |
| - :c:func:`iob_concat()` |
| - :c:func:`iob_trimhead()` |
| - :c:func:`iob_trimhead_queue()` |
| - :c:func:`iob_trimtail()` |
| - :c:func:`iob_pack()` |
| - :c:func:`iob_contig()` |
| - :c:func:`iob_dump()` |
| |
| .. c:function:: void iob_initialize(void); |
| |
| Set up the I/O buffers for normal operations. |
| |
| .. c:function:: FAR struct iob_s *iob_alloc(bool throttled); |
| |
| Allocate an I/O buffer by taking the buffer at |
| the head of the free list. |
| |
| .. c:function:: FAR struct iob_s *iob_tryalloc(bool throttled); |
| |
| Try to allocate an I/O buffer by taking the |
| buffer at the head of the free list without waiting for a buffer |
| to become free. |
| |
| .. c:function:: FAR struct iob_s *iob_free(FAR struct iob_s *iob, \ |
| enum iob_user_e producerid); |
| |
| Free the I/O buffer at the head of a buffer chain |
| returning it to the free list. The link to the next I/O buffer in |
| the chain is return. |
| |
| .. c:function:: void iob_free_chain(FAR struct iob_s *iob, \ |
| enum iob_user_e producerid); |
| |
| Free an entire buffer chain, starting at the |
| beginning of the I/O buffer chain |
| |
| .. c:function:: int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq) |
| |
| Add one I/O buffer chain to the end of a queue. |
| May fail due to lack of resources. |
| |
| .. c:function:: void iob_tryadd_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq) |
| |
| Add one I/O buffer chain to the end of a queue |
| without waiting for resources to become free. |
| |
| .. c:function:: FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq); |
| |
| Remove and return one I/O buffer chain from the |
| head of a queue. |
| |
| :return: Returns a reference to the I/O buffer chain at |
| the head of the queue. |
| |
| .. c:function:: FAR struct iob_s *iob_peek_queue(FAR struct iob_queue_s *iobq) |
| |
| Return a reference to the I/O buffer chain at the |
| head of a queue. This is similar to iob_remove_queue except that |
| the I/O buffer chain is in place at the head of the queue. The I/O |
| buffer chain may safely be modified by the caller but must be |
| removed from the queue before it can be freed. |
| |
| :return: Returns a reference to the I/O buffer chain at |
| the head of the queue. |
| |
| .. c:function:: void iob_free_queue(FAR struct iob_queue_s *qhead, \ |
| enum iob_user_e producerid); |
| |
| Free an entire queue of I/O buffer chains. |
| |
| .. c:function:: void iob_free_queue_qentry(FAR struct iob_s *iob, \ |
| FAR struct iob_queue_s *iobq); |
| |
| Queue helper for get the iob queue buffer size. |
| |
| .. c:function:: unsigned int iob_get_queue_size(FAR struct iob_queue_s *queue); |
| |
| Free an iob entire queue of I/O buffer chains. |
| |
| .. c:function:: int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, \ |
| unsigned int len, unsigned int offset, bool throttled); |
| |
| Copy data ``len`` bytes from a user buffer into |
| the I/O buffer chain, starting at ``offset``, extending the chain |
| as necessary. |
| |
| .. c:function:: int iob_trycopyin(FAR struct iob_s *iob, FAR const uint8_t *src, \ |
| unsigned int len, unsigned int offset, bool throttled); |
| |
| Copy data ``len`` bytes from a user buffer into |
| the I/O buffer chain, starting at ``offset``, extending the chain |
| as necessary BUT without waiting if buffers are not available. |
| |
| .. c:function:: int iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, \ |
| unsigned int len, unsigned int offset); |
| |
| Copy data ``len`` bytes of data into the user |
| buffer starting at ``offset`` in the I/O buffer, returning that |
| actual number of bytes copied out. |
| |
| .. c:function:: int iob_clone(FAR struct iob_s *iob1, FAR struct iob_s *iob2, bool throttled) |
| |
| Duplicate (and pack) the data in ``iob1`` in |
| ``iob2``. ``iob2`` must be empty. |
| |
| .. c:function:: void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2) |
| |
| Concatenate iob_s chain iob2 to iob1. |
| |
| .. c:function:: FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, \ |
| unsigned int trimlen, enum iob_user_e producerid) |
| |
| Remove bytes from the beginning of an I/O chain. |
| Emptied I/O buffers are freed and, hence, the beginning of the |
| chain may change. |
| |
| .. c:function:: FAR struct iob_s *iob_trimhead_queue(FAR struct iob_queue_s *qhead, \ |
| unsigned int trimlen, enum iob_user_e producerid); |
| |
| Remove bytes from the beginning of an I/O chain |
| at the head of the queue. Emptied I/O buffers are freed and, |
| hence, the head of the queue may change. |
| |
| This function is just a wrapper around iob_trimhead() that assures |
| that the iob at the head of queue is modified with the trimming |
| operations. |
| |
| :return: The new iob at the head of the queue is |
| returned. |
| |
| .. c:function:: FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, \ |
| unsigned int trimlen, enum iob_user_e producerid); |
| |
| Remove bytes from the end of an I/O chain. |
| Emptied I/O buffers are freed NULL will be returned in the special |
| case where the entry I/O buffer chain is freed. |
| |
| .. c:function:: FAR struct iob_s *iob_pack(FAR struct iob_s *iob, \ |
| enum iob_user_e producerid); |
| |
| Pack all data in the I/O buffer chain so that the |
| data offset is zero and all but the final buffer in the chain are |
| filled. Any emptied buffers at the end of the chain are freed. |
| |
| .. c:function:: int iob_contig(FAR struct iob_s *iob, unsigned int len, \ |
| enum iob_user_e producerid); |
| |
| Ensure that there is ``len`` bytes of contiguous |
| space at the beginning of the I/O buffer chain starting at |
| ``iob``. |
| |
| .. c:function:: void iob_dump(FAR const char *msg, FAR struct iob_s *iob, unsigned int len, \ |
| unsigned int offset); |
| |
| Dump the contents of a I/O buffer chain |
| |