QNativeSocketEngine: reduce memory usage in nativePendingDatagramSize()
The Windows implementation had the right idea: by using a chunked read, we can tell the OS to reuse the same buffer over and over, so we don't need to grow a buffer to the size of the datagram when peeking. This commit implements that strategy on Unix and changes both implementations to start at 1500 bytes instead of 8192 (1500 is more than enough for almost all datagrams we're going to receive). Let's also not use a static buffer, but a stack-based one. No need to dedicate 1500 (or, worse, 8192) bytes for something that is only seldom called. Change-Id: I320d9d2f42284a69a4cbfffd14dd92a6775bf28b Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
3b61cd6ad7
commit
a9ff368ac7
@ -868,22 +868,42 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
|
|||||||
if (recvResult != -1)
|
if (recvResult != -1)
|
||||||
recvResult = value;
|
recvResult = value;
|
||||||
#else
|
#else
|
||||||
QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192);
|
// We need to grow the buffer to fit the entire datagram.
|
||||||
|
// We start at 1500 bytes (the MTU for Ethernet V2), which should catch
|
||||||
|
// almost all uses (effective MTU for UDP under IPv4 is 1468), except
|
||||||
|
// for localhost datagrams and those reassembled by the IP layer.
|
||||||
|
char udpMessagePeekBuffer[1500];
|
||||||
|
struct msghdr msg;
|
||||||
|
struct iovec vec;
|
||||||
|
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
msg.msg_iov = &vec;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
vec.iov_base = udpMessagePeekBuffer;
|
||||||
|
vec.iov_len = sizeof(udpMessagePeekBuffer);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// the data written to udpMessagePeekBuffer is discarded, so
|
// the data written to udpMessagePeekBuffer is discarded, so
|
||||||
// this function is still reentrant although it might not look
|
// this function is still reentrant although it might not look
|
||||||
// so.
|
// so.
|
||||||
recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(),
|
recvResult = ::recvmsg(socketDescriptor, &msg, MSG_PEEK);
|
||||||
udpMessagePeekBuffer.size(), MSG_PEEK);
|
|
||||||
if (recvResult == -1 && errno == EINTR)
|
if (recvResult == -1 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (recvResult != (ssize_t) udpMessagePeekBuffer.size())
|
// was the result truncated?
|
||||||
|
if ((msg.msg_flags & MSG_TRUNC) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2);
|
// grow by 16 times
|
||||||
|
msg.msg_iovlen *= 16;
|
||||||
|
if (msg.msg_iov != &vec)
|
||||||
|
delete[] msg.msg_iov;
|
||||||
|
msg.msg_iov = new struct iovec[msg.msg_iovlen];
|
||||||
|
std::fill_n(msg.msg_iov, msg.msg_iovlen, vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg.msg_iov != &vec)
|
||||||
|
delete[] msg.msg_iov;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
#if defined (QNATIVESOCKETENGINE_DEBUG)
|
||||||
|
@ -1146,10 +1146,10 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
|
|||||||
DWORD bufferCount = 5;
|
DWORD bufferCount = 5;
|
||||||
WSABUF * buf = 0;
|
WSABUF * buf = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// the data written to udpMessagePeekBuffer is discarded, so
|
// We start at 1500 bytes (the MTU for Ethernet V2), which should catch
|
||||||
// this function is still reentrant although it might not look
|
// almost all uses (effective MTU for UDP under IPv4 is 1468), except
|
||||||
// so.
|
// for localhost datagrams and those reassembled by the IP layer.
|
||||||
static char udpMessagePeekBuffer[8192];
|
char udpMessagePeekBuffer[1500];
|
||||||
|
|
||||||
buf = new WSABUF[bufferCount];
|
buf = new WSABUF[bufferCount];
|
||||||
for (DWORD i=0; i<bufferCount; i++) {
|
for (DWORD i=0; i<bufferCount; i++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user