📄 uploadbandwidththrottler.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include <math.h>
#include "emule.h"
#include "UploadBandwidthThrottler.h"
#include "EMSocket.h"
#include "opcodes.h"
#include "LastCommonRouteFinder.h"
#include "OtherFunctions.h"
#include "emuledlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
/**
* The constructor starts the thread.
*/
UploadBandwidthThrottler::UploadBandwidthThrottler(void) {
m_SentBytesSinceLastCall = 0;
m_SentBytesSinceLastCallOverhead = 0;
m_highestNumberOfFullyActivatedSlots = 0;
threadEndedEvent = new CEvent(0, 1);
pauseEvent = new CEvent(TRUE, TRUE);
doRun = true;
AfxBeginThread(RunProc, (LPVOID)this);
}
/**
* The destructor stops the thread. If the thread has already stoppped, destructor does nothing.
*/
UploadBandwidthThrottler::~UploadBandwidthThrottler(void) {
EndThread();
delete threadEndedEvent;
delete pauseEvent;
}
void UploadBandwidthThrottler::SetAllowedDataRate(uint32 newValue) {
sendLocker.Lock();
m_allowedDataRate = newValue;
sendLocker.Unlock();
}
/**
* Find out how many bytes that has been put on the sockets since the last call to this
* method. Includes overhead of control packets.
*
* @return the number of bytes that has been put on the sockets since the last call
*/
uint64 UploadBandwidthThrottler::GetNumberOfSentBytesSinceLastCallAndReset() {
sendLocker.Lock();
uint64 numberOfSentBytesSinceLastCall = m_SentBytesSinceLastCall;
m_SentBytesSinceLastCall = 0;
sendLocker.Unlock();
return numberOfSentBytesSinceLastCall;
}
/**
* Find out how many bytes that has been put on the sockets since the last call to this
* method. Excludes overhead of control packets.
*
* @return the number of bytes that has been put on the sockets since the last call
*/
uint64 UploadBandwidthThrottler::GetNumberOfSentBytesOverheadSinceLastCallAndReset() {
sendLocker.Lock();
uint64 numberOfSentBytesSinceLastCall = m_SentBytesSinceLastCallOverhead;
m_SentBytesSinceLastCallOverhead = 0;
sendLocker.Unlock();
return numberOfSentBytesSinceLastCall;
}
/**
* Find out the highest number of slots that has been fed data in the normal standard loop
* of the thread since the last call of this method. This means all slots that haven't
* been in the trickle state during the entire time since the last call.
*
* @return the highest number of fully activated slots during any loop since last call
*/
uint32 UploadBandwidthThrottler::GetHighestNumberOfFullyActivatedSlotsSinceLastCallAndReset() {
sendLocker.Lock();
//if(m_highestNumberOfFullyActivatedSlots > (uint32)m_StandardOrder_list.GetSize()) {
// theApp.QueueDebugLogLine(true, _T("UploadBandwidthThrottler: Throttler wants new slot when get-method called. m_highestNumberOfFullyActivatedSlots: %i m_StandardOrder_list.GetSize(): %i tick: %i"), m_highestNumberOfFullyActivatedSlots, m_StandardOrder_list.GetSize(), ::GetTickCount());
//}
uint32 highestNumberOfFullyActivatedSlots = m_highestNumberOfFullyActivatedSlots;
m_highestNumberOfFullyActivatedSlots = 0;
sendLocker.Unlock();
return highestNumberOfFullyActivatedSlots;
}
/**
* Add a socket to the list of sockets that have upload slots. The main thread will
* continously call send on these sockets, to give them chance to work off their queues.
* The sockets are called in the order they exist in the list, so the top socket (index 0)
* will be given a chance first to use bandwidth, and then the next socket (index 1) etc.
*
* It is possible to add a socket several times to the list without removing it inbetween,
* but that should be avoided.
*
* @param index insert the socket at this place in the list. An index that is higher than the
* current number of sockets in the list will mean that the socket should be inserted
* last in the list.
*
* @param socket the address to the socket that should be added to the list. If the address is NULL,
* this method will do nothing.
*/
void UploadBandwidthThrottler::AddToStandardList(uint32 index, ThrottledFileSocket* socket) {
if(socket != NULL) {
sendLocker.Lock();
RemoveFromStandardListNoLock(socket);
if(index > (uint32)m_StandardOrder_list.GetSize()) {
index = m_StandardOrder_list.GetSize();
}
m_StandardOrder_list.InsertAt(index, socket);
sendLocker.Unlock();
// } else {
// if (thePrefs.GetVerbose())
// theApp.AddDebugLogLine(true,"Tried to add NULL socket to UploadBandwidthThrottler Standard list! Prevented.");
}
}
/**
* Remove a socket from the list of sockets that have upload slots.
*
* If the socket has mistakenly been added several times to the list, this method
* will return all of the entries for the socket.
*
* @param socket the address of the socket that should be removed from the list. If this socket
* does not exist in the list, this method will do nothing.
*/
bool UploadBandwidthThrottler::RemoveFromStandardList(ThrottledFileSocket* socket) {
bool returnValue;
sendLocker.Lock();
returnValue = RemoveFromStandardListNoLock(socket);
sendLocker.Unlock();
return returnValue;
}
/**
* Remove a socket from the list of sockets that have upload slots. NOT THREADSAFE!
* This is an internal method that doesn't take the necessary lock before it removes
* the socket. This method should only be called when the current thread already owns
* the sendLocker lock!
*
* @param socket address of the socket that should be removed from the list. If this socket
* does not exist in the list, this method will do nothing.
*/
bool UploadBandwidthThrottler::RemoveFromStandardListNoLock(ThrottledFileSocket* socket) {
// Find the slot
int slotCounter = 0;
bool foundSocket = false;
while(slotCounter < m_StandardOrder_list.GetSize() && foundSocket == false) {
if(m_StandardOrder_list.GetAt(slotCounter) == socket) {
// Remove the slot
m_StandardOrder_list.RemoveAt(slotCounter);
foundSocket = true;
} else {
slotCounter++;
}
}
if(foundSocket && m_highestNumberOfFullyActivatedSlots > (uint32)m_StandardOrder_list.GetSize()) {
m_highestNumberOfFullyActivatedSlots = m_StandardOrder_list.GetSize();
}
return foundSocket;
}
/**
* Notifies the send thread that it should try to call controlpacket send
* for the supplied socket. It is allowed to call this method several times
* for the same socket, without having controlpacket send called for the socket
* first. The doublette entries are never filtered, since it is incurs less cpu
* overhead to simply call Send() in the socket for each double. Send() will
* already have done its work when the second Send() is called, and will just
* return with little cpu overhead.
*
* @param socket address to the socket that requests to have controlpacket send
* to be called on it
*/
void UploadBandwidthThrottler::QueueForSendingControlPacket(ThrottledControlSocket* socket, bool hasSent) {
// Get critical section
tempQueueLocker.Lock();
if(doRun) {
if(hasSent) {
m_TempControlQueueFirst_list.AddTail(socket);
} else {
m_TempControlQueue_list.AddTail(socket);
}
}
// End critical section
tempQueueLocker.Unlock();
}
/**
* Remove the socket from all lists and queues. This will make it safe to
* erase/delete the socket. It will also cause the main thread to stop calling
* send() for the socket.
*
* @param socket address to the socket that should be removed
*/
void UploadBandwidthThrottler::RemoveFromAllQueues(ThrottledControlSocket* socket, bool lock) {
if(lock) {
// Get critical section
sendLocker.Lock();
}
if(doRun) {
// Remove this socket from control packet queue
{
POSITION pos1, pos2;
for (pos1 = m_ControlQueue_list.GetHeadPosition();( pos2 = pos1 ) != NULL;) {
m_ControlQueue_list.GetNext(pos1);
ThrottledControlSocket* socketinQueue = m_ControlQueue_list.GetAt(pos2);
if(socketinQueue == socket) {
m_ControlQueue_list.RemoveAt(pos2);
}
}
}
{
POSITION pos1, pos2;
for (pos1 = m_ControlQueueFirst_list.GetHeadPosition();( pos2 = pos1 ) != NULL;) {
m_ControlQueueFirst_list.GetNext(pos1);
ThrottledControlSocket* socketinQueue = m_ControlQueueFirst_list.GetAt(pos2);
if(socketinQueue == socket) {
m_ControlQueueFirst_list.RemoveAt(pos2);
}
}
}
tempQueueLocker.Lock();
{
POSITION pos1, pos2;
for (pos1 = m_TempControlQueue_list.GetHeadPosition();( pos2 = pos1 ) != NULL;) {
m_TempControlQueue_list.GetNext(pos1);
ThrottledControlSocket* socketinQueue = m_TempControlQueue_list.GetAt(pos2);
if(socketinQueue == socket) {
m_TempControlQueue_list.RemoveAt(pos2);
}
}
}
{
POSITION pos1, pos2;
for (pos1 = m_TempControlQueueFirst_list.GetHeadPosition();( pos2 = pos1 ) != NULL;) {
m_TempControlQueueFirst_list.GetNext(pos1);
ThrottledControlSocket* socketinQueue = m_TempControlQueueFirst_list.GetAt(pos2);
if(socketinQueue == socket) {
m_TempControlQueueFirst_list.RemoveAt(pos2);
}
}
}
tempQueueLocker.Unlock();
}
if(lock) {
// End critical section
sendLocker.Unlock();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -