// // PacketQueue.cpp // libraries/networking/src/udt // // Created by Clement on 9/16/15. // Copyright 2015 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "PacketQueue.h" #include "PacketList.h" using namespace udt; PacketQueue::PacketQueue(MessageNumber messageNumber) : _currentMessageNumber(messageNumber) { _channels.emplace_front(new std::list()); _currentChannel = _channels.begin(); } MessageNumber PacketQueue::getNextMessageNumber() { static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE; _currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER; return _currentMessageNumber; } bool PacketQueue::isEmpty() const { LockGuard locker(_packetsLock); // Only the main channel and it is empty return _channels.size() == 1 && _channels.front()->empty(); } PacketQueue::PacketPointer PacketQueue::takePacket() { LockGuard locker(_packetsLock); if (isEmpty()) { return PacketPointer(); } // handle the case where we are looking at the first channel and it is empty if (_currentChannel == _channels.begin() && (*_currentChannel)->empty()) { ++_currentChannel; } // at this point the current channel should always not be at the end and should also not be empty Q_ASSERT(_currentChannel != _channels.end()); auto& channel = *_currentChannel; Q_ASSERT(!channel->empty()); // Take front packet auto packet = std::move(channel->front()); channel->pop_front(); // Remove now empty channel (Don't remove the main channel) if (channel->empty() && _currentChannel != _channels.begin()) { // erase the current channel and slide the iterator to the next channel _currentChannel = _channels.erase(_currentChannel); } else { ++_currentChannel; } // push forward our number of channels taken from ++_channelsVisitedCount; // check if we need to restart back at the front channel (main) // to respect our capped number of channels considered concurrently static const int MAX_CHANNELS_SENT_CONCURRENTLY = 16; if (_currentChannel == _channels.end() || _channelsVisitedCount >= MAX_CHANNELS_SENT_CONCURRENTLY) { _channelsVisitedCount = 0; _currentChannel = _channels.begin(); } return packet; } void PacketQueue::queuePacket(PacketPointer packet) { LockGuard locker(_packetsLock); _channels.front()->push_back(std::move(packet)); } void PacketQueue::queuePacketList(PacketListPointer packetList) { if (packetList->isOrdered()) { packetList->preparePackets(getNextMessageNumber()); } LockGuard locker(_packetsLock); _channels.emplace_back(new std::list()); _channels.back()->swap(packetList->_packets); }