diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-06-04 09:03:11 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-06-04 09:03:11 -0600 |
commit | f1eceaa766fe62c27bbbd455359238077eb970de (patch) | |
tree | 6b2a2ba892875297705ef6504dd89c258b2af4ee | |
parent | c6f0f268d5062fa0d40f64dbcdfa8a0103629d12 (diff) | |
download | px4-nuttx-f1eceaa766fe62c27bbbd455359238077eb970de.tar.gz px4-nuttx-f1eceaa766fe62c27bbbd455359238077eb970de.tar.bz2 px4-nuttx-f1eceaa766fe62c27bbbd455359238077eb970de.zip |
NET: Improvied I/O buffer logic
-rw-r--r-- | nuttx/include/nuttx/net/iob.h | 31 | ||||
-rw-r--r-- | nuttx/net/iob/iob_alloc.c | 3 | ||||
-rw-r--r-- | nuttx/net/iob/iob_concat.c | 78 | ||||
-rw-r--r-- | nuttx/net/iob/iob_copyin.c | 26 | ||||
-rw-r--r-- | nuttx/net/iob/iob_copyout.c | 2 | ||||
-rw-r--r-- | nuttx/net/iob/iob_trimhead.c | 63 | ||||
-rw-r--r-- | nuttx/net/iob/iob_trimtail.c | 29 |
7 files changed, 124 insertions, 108 deletions
diff --git a/nuttx/include/nuttx/net/iob.h b/nuttx/include/nuttx/net/iob.h index 714b4fd80..29457aa3e 100644 --- a/nuttx/include/nuttx/net/iob.h +++ b/nuttx/include/nuttx/net/iob.h @@ -41,6 +41,10 @@ ****************************************************************************/ #include <nuttx/config.h> + +#include <stdint.h> +#include <queue.h> + #include <nuttx/net/iob.h> /**************************************************************************** @@ -57,7 +61,8 @@ ****************************************************************************/ /* Represents one I/O buffer. A packet is contained by one or more I/O - * buffers in a chain. + * buffers in a chain. The io_flags, io_pktlen, io_vtag and io_priv + * fields are only valid for the I/O buffer at the head of the chain. */ struct iob_s @@ -65,6 +70,7 @@ struct iob_s sq_entry_t io_link; /* Link to the next I/O buffer in the chain */ uint8_t io_flags; /* Flags associated with the I/O buffer */ uint16_t io_len; /* Length of the data in the entry */ + uint16_t io_offset; /* Data begins at this offset */ uint16_t io_pktlen; /* Total length of the packet */ uint16_t io_vtag; /* VLAN tag */ void *io_priv; /* User private data attached to the I/O buffer */ @@ -146,20 +152,35 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2); * Name: iob_trimhead * * Description: - * Remove bytes from the beginning of an I/O chain + * 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. * ****************************************************************************/ -void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen); +FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen); /**************************************************************************** * Name: iob_trimtail * * Description: - * Remove bytes from the end of an I/O chain + * 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. + * + ****************************************************************************/ + +FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen); + +/**************************************************************************** + * Name: iob_pack + * + * Description: + * 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. * ****************************************************************************/ -void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen); +FAR struct iob_s *iob_pack(FAR struct iob_s *iob); #endif /* _INCLUDE_NUTTX_NET_IOB_H */ diff --git a/nuttx/net/iob/iob_alloc.c b/nuttx/net/iob/iob_alloc.c index 390883c83..91106d4d5 100644 --- a/nuttx/net/iob/iob_alloc.c +++ b/nuttx/net/iob/iob_alloc.c @@ -80,9 +80,10 @@ FAR struct iob_s *iob_alloc(void) iob = (FAR struct iob_s *)sq_remfirst(&g_iob_freelist); if (iob) { - iob->io_link.flink = NULL; /* Not in a list */ + iob->io_link.flink = NULL; /* Not in a chain */ iob->io_flags = 0; /* Flags associated with the I/O buffer */ iob->io_len = 0; /* Length of the data in the entry */ + iob->io_offset = 0; /* Offset to the beginning of data */ iob->io_pktlen = 0; /* Total length of the packet */ iob->io_vtag = 0; /* VLAN tag */ iob->io_priv = NULL; /* User private data attached to the I/O buffer */ diff --git a/nuttx/net/iob/iob_concat.c b/nuttx/net/iob/iob_concat.c index d7b03e1fc..a18d0e35e 100644 --- a/nuttx/net/iob/iob_concat.c +++ b/nuttx/net/iob/iob_concat.c @@ -76,10 +76,6 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2) { - unsigned int offset2; - unsigned int ncopy; - unsigned int navail; - /* Find the last buffer in the iob1 buffer chain */ while (iob1->io_link.flink) @@ -87,72 +83,16 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2) iob1 = (FAR struct iob_s *)iob1->io_link.flink; } - /* Then add data to the end of iob1 */ - - offset2 = 0; - while (iob2) - { - /* Is the iob1 tail buffer full? */ - - if (iob1->io_len >= CONFIG_IOB_BUFSIZE) - { - /* Yes.. Just connect the chains */ - - iob1->io_link.flink = iob2->io_link.flink; - - /* Has the data offset in iob2? */ - - if (offset2 > 0) - { - /* Yes, move the data down and adjust the size */ - - iob2->io_len -= offset2; - memcpy(iob2->io_data, &iob2->io_data[offset2], iob2->io_len); - - /* Set up to continue packing, but now into iob2 */ - - iob1 = iob2; - iob2 = (FAR struct iob_s *)iob2->io_link.flink; + /* Then connect iob2 buffer chain to the end of the iob1 chain */ - iob1->io_link.flink = NULL; - offset2 = 0; - } - else - { - /* Otherwise, we are done */ + iob1->io_link.flink = iob2->io_link.flink; - return; - } - } + /* Combine the total packet size. flags, VLAN, tags, and private + * data from iob2 are lost. + */ - /* How many bytes can we copy from the source (iob2) */ - - ncopy = iob2->io_len - offset2; - - /* Limit the size of the copy to the amount of free space in iob1 */ - - navail = CONFIG_IOB_BUFSIZE - iob1->io_len; - if (ncopy > navail) - { - ncopy = navail; - } - - /* Copy the data from iob2 into iob1 */ - - memcpy(iob1->io_data + iob1->io_len, iob2->io_data, ncopy); - iob1->io_len += ncopy; - offset2 += ncopy; - - /* Have we consumed all of the data in the iob2 entry? */ - - if (offset2 >= iob2->io_len) - { - /* Yes.. free the iob2 entry and start processing the next I/O - * buffer in the iob2 chain. - */ - - iob2 = iob_free(iob2); - offset2 = 0; - } - } + iob1->io_pktlen += iob2->io_pktlen; + iob2->io_flags = 0; + iob2->io_vtag = 0; + iob2->io_priv = NULL; } diff --git a/nuttx/net/iob/iob_copyin.c b/nuttx/net/iob/iob_copyin.c index d48518679..34c76bc69 100644 --- a/nuttx/net/iob/iob_copyin.c +++ b/nuttx/net/iob/iob_copyin.c @@ -85,11 +85,12 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, unsigned int len, unsigned int offset) { + FAR struct iob_s *head = iob; FAR uint8_t *dest; unsigned int ncopy; unsigned int avail; - /* Skip to the I/O buffer containing the offset */ + /* Skip to the I/O buffer containing the data offset */ while (offset >= iob->io_len) { @@ -101,16 +102,18 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, while (len > 0) { - /* Get the source I/O buffer offset address and the amount of data - * available from that address. + /* Get the destination I/O buffer address and the amount of data + * available from that address. We don't want to extend the length + * an I/O buffer here. */ - dest = &iob->io_data[offset]; - avail = CONFIG_IOB_BUFSIZE - offset; + dest = &iob->io_data[iob->io_offset + offset]; + avail = iob->io_len - offset; - /* Copy from the user buffer to the I/O buffer */ + /* Copy from the user buffer to the I/O buffer + */ - ncopy = MIN(avail, len); + ncopy = MIN(len, avail); memcpy(dest, src, ncopy); /* Adjust the total length of the copy and the destination address in @@ -127,6 +130,7 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, if (iob->io_link.flink == NULL) { struct iob_s *newiob; + unsigned int newlen; /* Yes.. allocate a new buffer */ @@ -140,7 +144,13 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, /* Add the new I/O buffer to the end of the buffer chain. */ iob->io_link.flink = &newiob->io_link; - iob = newiob; + iob = newiob; + + /* The additional bytes extend the length of the packet */ + + newlen = MIN(len, CONFIG_IOB_BUFSIZE); + iob->io_len = newlen; + head->io_pktlen += newlen; } else { diff --git a/nuttx/net/iob/iob_copyout.c b/nuttx/net/iob/iob_copyout.c index 81512c38b..d10356150 100644 --- a/nuttx/net/iob/iob_copyout.c +++ b/nuttx/net/iob/iob_copyout.c @@ -106,7 +106,7 @@ void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, * available from that address. */ - src = &iob->io_data[offset]; + src = &iob->io_data[iob->io_offset + offset]; avail = iob->io_len - offset; /* Copy the from the I/O buffer in to the user buffer */ diff --git a/nuttx/net/iob/iob_trimhead.c b/nuttx/net/iob/iob_trimhead.c index ef6e1c2f6..a4e47ac2e 100644 --- a/nuttx/net/iob/iob_trimhead.c +++ b/nuttx/net/iob/iob_trimhead.c @@ -39,9 +39,6 @@ #include <nuttx/config.h> -#include <string.h> -#include <queue.h> - #include <nuttx/net/iob.h> #include "iob.h" @@ -70,33 +67,55 @@ * Name: iob_trimhead * * Description: - * Remove bytes from the beginning of an I/O chain + * 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. * ****************************************************************************/ -void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) +FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) { FAR struct iob_s *entry; + uint8_t flags; + uint16_t pktlen; + uint16_t vtag; + void *priv; unsigned int len; if (iob && trimlen > 0) { - entry = iob; - len = trimlen; + /* Save information from the head of the chain (in case the + * head is removed). + */ + + flags = iob->io_flags; + pktlen = iob->io_pktlen; + vtag = iob->io_vtag; + priv = iob->io_priv; /* Trim from the head of the I/IO buffer chain */ - while (entry != NULL && len > 0) + entry = iob; + len = trimlen; + + while (entry != NULL) { /* Do we trim this entire I/O buffer away? */ if (entry->io_len <= len) { - /* Yes.. just set is length to zero and skip to the next */ + /* Decrement the trim length by the full data size */ + + pktlen -= entry->io_len; + len -= entry->io_len; + + /* Free this one and set the next I/O buffer as the head */ - len -= entry->io_len; - entry->io_len = 0; - entry = (FAR struct iob_s *)entry->io_link.flink; + iob = (FAR struct iob_s *)entry->io_link.flink; + iob_free(entry); + + /* Continue with the new buffer head */ + + entry = iob; } else { @@ -104,10 +123,26 @@ void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) * stop the trim. */ - entry->io_len -= len; - memcpy(entry->io_data, &entry->io_data[len], entry->io_len); + pktlen -= len; + entry->io_len -= len; + entry->io_offset += len; len = 0; } } + + /* Restore the state to the head of the chain (which may not be + * the same I/O buffer chain head that we started with). + * + * Adjust the pktlen by the number of bytes removed from the head + * of the I/O buffer chain. A special case is where we delete the + * entire chain: len > 0 and iob == NULL. + */ + + iob->io_flags = flags; + iob->io_pktlen = pktlen; + iob->io_vtag = vtag; + iob->io_priv = priv; } + + return iob; } diff --git a/nuttx/net/iob/iob_trimtail.c b/nuttx/net/iob/iob_trimtail.c index 030042be9..6c8901847 100644 --- a/nuttx/net/iob/iob_trimtail.c +++ b/nuttx/net/iob/iob_trimtail.c @@ -74,8 +74,9 @@ * ****************************************************************************/ -void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen) +FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen) { + FAR struct iob_s *head = iob; FAR struct iob_s *entry; FAR struct iob_s *penultimate; FAR struct iob_s *last; @@ -118,21 +119,27 @@ void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen) if (last->io_len <= len) { - /* Yes.. just set is length to zero and skip to the next */ + /* Yes.. Consume the entire buffer */ - len -= last->io_len; - last->io_len = 0; + head->io_pktlen -= last->io_len; + len -= last->io_len; + last->io_len = 0; + + /* Free the last, empty buffer in the list */ + + iob_free(last); /* There should be a buffer before this one */ if (!penultimate) { - return; + /* No.. we just freed the head of the chain */ + + return NULL; } - /* Free the last, empty buffer in the list */ + /* Unlink the penultimate from the freed buffer */ - iob_free(last); penultimate->io_link.flink = NULL; } @@ -142,10 +149,12 @@ void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen) * stop the trim. */ - last->io_len -= len; - memcpy(last->io_data, &last->io_data[len], last->io_len); - len = 0; + head->io_pktlen -= last->io_len; + last->io_len -= len; + len = 0; } } } + + return iob; } |