You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktorrent/libktorrent/net/networkthread.cpp

166 lines
4.5 KiB

/***************************************************************************
* Copyright (C) 2005 by Joris Guisson *
* joris.guisson@gmail.com *
* *
* 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., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <math.h>
#include <util/functions.h>
#include <util/log.h>
#include "socketgroup.h"
#include "socketmonitor.h"
#include "networkthread.h"
using namespace bt;
namespace net
{
NetworkThread::NetworkThread(SocketMonitor* sm)
: sm(sm),running(false)
{
groups.setAutoDelete(true);
groups.insert(0,new SocketGroup(0));
}
NetworkThread::~NetworkThread()
{}
void NetworkThread::run()
{
running = true;
prev_run_time = bt::Now();
while (running)
update();
}
void NetworkThread::addGroup(Uint32 gid,Uint32 limit)
{
// if group already exists, just change the limit
SocketGroup* g = groups.find(gid);
if (g)
{
g->setLimit(limit);
}
else
{
g = new SocketGroup(limit);
groups.insert(gid,g);
}
}
void NetworkThread::removeGroup(Uint32 gid)
{
// make sure the 0 group is never erased
if (gid != 0)
groups.erase(gid);
}
void NetworkThread::setGroupLimit(Uint32 gid,Uint32 limit)
{
SocketGroup* g = groups.find(gid);
if (g)
{
g->setLimit(limit);
}
}
Uint32 NetworkThread::doGroupsLimited(Uint32 num_ready,bt::TimeStamp now,Uint32 & allowance)
{
Uint32 num_still_ready = 0;
// this is one pass over all the groups
bt::PtrMap<Uint32,SocketGroup>::iterator itr = groups.begin();
while (itr != groups.end() && allowance > 0)
{
SocketGroup* g = itr->second;
if (g->numSockets() > 0)
{
Uint32 group_allowance = (Uint32)ceil(((double)g->numSockets() / num_ready) * allowance);
// lets not do to much and make sure we don't pass 0 to the socket group (0 is unlimited)
if (group_allowance > allowance || group_allowance == 0)
group_allowance = allowance;
Uint32 ga = group_allowance;
if (!doGroup(g,ga,now))
g->clear(); // group is done, so clear it
else
num_still_ready += g->numSockets(); // keep track of the number of sockets which are still ready
Uint32 done = group_allowance - ga;
if (allowance >= done)
allowance -= done;
else
allowance = 0;
}
itr++;
}
return num_still_ready > 0;
}
void NetworkThread::doGroups(Uint32 num_ready,bt::TimeStamp now,bt::Uint32 limit)
{
if (limit == 0)
{
Uint32 allowance = 0;
bt::PtrMap<Uint32,SocketGroup>::iterator itr = groups.begin();
while (itr != groups.end())
{
SocketGroup* g = itr->second;
if (g->numSockets() > 0)
{
g->calcAllowance(now);
doGroup(g,allowance,now);
g->clear();
}
itr++;
}
}
else
{
// calculate group allowance for each group
bt::PtrMap<Uint32,SocketGroup>::iterator itr = groups.begin();
while (itr != groups.end())
{
SocketGroup* g = itr->second;
g->calcAllowance(now);
itr++;
}
Uint32 allowance = (Uint32)ceil(1.02 * limit * (now - prev_run_time) * 0.001);
while (allowance > 0 && num_ready > 0)
{
// loop until nobody is ready anymore or the allowance is up
num_ready = doGroupsLimited(num_ready,now,allowance);
}
// make sure all groups are cleared
itr = groups.begin();
while (itr != groups.end())
{
SocketGroup* g = itr->second;
g->clear();
itr++;
}
}
}
}