Exemplo n.º 1
0
/**
 * The thread method that handles calling send for the individual sockets.
 *
 * Control packets will always be tried to be sent first. If there is any bandwidth leftover
 * after that, send() for the upload slot sockets will be called in priority order until we have run
 * out of available bandwidth for this loop. Upload slots will not be allowed to go without having sent
 * called for more than a defined amount of time (i.e. two seconds).
 *
 * @return always returns 0.
 */
void* UploadBandwidthThrottler::Entry()
{
	const uint32 TIME_BETWEEN_UPLOAD_LOOPS = 1;
	
	uint32 lastLoopTick = GetTickCountFullRes();
	// Bytes to spend in current cycle. If we spend more this becomes negative and causes a wait next time.
	sint32 bytesToSpend = 0;
	uint32 allowedDataRate = 0;
	uint32 rememberedSlotCounter = 0;
	uint32 extraSleepTime = TIME_BETWEEN_UPLOAD_LOOPS;
	
	while (m_doRun && !TestDestroy()) {
		uint32 timeSinceLastLoop = GetTickCountFullRes() - lastLoopTick;

		// Calculate data rate
		if (thePrefs::GetMaxUpload() == UNLIMITED) {
			// Try to increase the upload rate from UploadSpeedSense
			allowedDataRate = (uint32)theStats::GetUploadRate() + 5 * 1024;
		} else {
			allowedDataRate = thePrefs::GetMaxUpload() * 1024;
		}

		uint32 minFragSize = 1300;
		uint32 doubleSendSize = minFragSize*2; // send two packages at a time so they can share an ACK
		if (allowedDataRate < 6*1024) {
			minFragSize = 536;
			doubleSendSize = minFragSize; // don't send two packages at a time at very low speeds to give them a smoother load
		}


		uint32 sleepTime;
		if (bytesToSpend < 1) {
			// We have sent more than allowed in last cycle so we have to wait now
			// until we can send at least 1 byte.
			sleepTime = std::max((-bytesToSpend + 1) * 1000 / allowedDataRate + 2, // add 2 ms to allow for rounding inaccuracies
									extraSleepTime);
		} else {
			// We could send at once, but sleep a while to not suck up all cpu
			sleepTime = extraSleepTime;
		}

		if (timeSinceLastLoop < sleepTime) {
			Sleep(sleepTime-timeSinceLastLoop);
		}

		// Check after sleep in case the thread has been signaled to end
		if (!m_doRun || TestDestroy()) {
			break;
		}

		const uint32 thisLoopTick = GetTickCountFullRes();
		timeSinceLastLoop = thisLoopTick - lastLoopTick;
		lastLoopTick = thisLoopTick;

		if (timeSinceLastLoop > sleepTime + 2000) {
			AddDebugLogLineN(logGeneral, CFormat(wxT("UploadBandwidthThrottler: Time since last loop too long. time: %ims wanted: %ims Max: %ims")) 
				% timeSinceLastLoop % sleepTime % (sleepTime + 2000));

			timeSinceLastLoop = sleepTime + 2000;
		}

		// Calculate how many bytes we can spend

		bytesToSpend += (sint32) (allowedDataRate / 1000.0 * timeSinceLastLoop);

		if (bytesToSpend >= 1) {
			sint32 spentBytes = 0;
			sint32 spentOverhead = 0;

			wxMutexLocker sendLock(m_sendLocker);

			{
				wxMutexLocker queueLock(m_tempQueueLocker);

				// are there any sockets in m_TempControlQueue_list? Move them to normal m_ControlQueue_list;
				m_ControlQueueFirst_list.insert(	m_ControlQueueFirst_list.end(),
													m_TempControlQueueFirst_list.begin(),
													m_TempControlQueueFirst_list.end() );

				m_ControlQueue_list.insert( m_ControlQueue_list.end(), 
											m_TempControlQueue_list.begin(),
											m_TempControlQueue_list.end() );

				m_TempControlQueue_list.clear();
				m_TempControlQueueFirst_list.clear();
			}
	
			// Send any queued up control packets first
			while (spentBytes < bytesToSpend && (!m_ControlQueueFirst_list.empty() || !m_ControlQueue_list.empty())) {
				ThrottledControlSocket* socket = NULL;
	
				if (!m_ControlQueueFirst_list.empty()) {
					socket = m_ControlQueueFirst_list.front();
					m_ControlQueueFirst_list.pop_front();
				} else if (!m_ControlQueue_list.empty()) {
					socket = m_ControlQueue_list.front();
					m_ControlQueue_list.pop_front();
				}
	
				if (socket != NULL) {
					SocketSentBytes socketSentBytes = socket->SendControlData(bytesToSpend-spentBytes, minFragSize);
					spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
					spentOverhead += socketSentBytes.sentBytesControlPackets;
				}
			}
	
			// Check if any sockets haven't gotten data for a long time. Then trickle them a package.
			uint32 slots = m_StandardOrder_list.size();
			for (uint32 slotCounter = 0; slotCounter < slots; slotCounter++) {
				ThrottledFileSocket* socket = m_StandardOrder_list[ slotCounter ];
	
				if (socket != NULL) {
					if (thisLoopTick-socket->GetLastCalledSend() > SEC2MS(1)) {
						// trickle
						uint32 neededBytes = socket->GetNeededBytes();
	
						if (neededBytes > 0) {
							SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize);
							spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
							spentOverhead += socketSentBytes.sentBytesControlPackets;
						}
					}
				} else {
					AddDebugLogLineN(logGeneral, CFormat( wxT("There was a NULL socket in the UploadBandwidthThrottler Standard list (trickle)! Prevented usage. Index: %i Size: %i"))
						% slotCounter % m_StandardOrder_list.size());
				}
			}
	
			// Give available bandwidth to slots, starting with the one we ended with last time.
			// There are two passes. First pass gives packets of doubleSendSize, second pass
			// gives as much as possible.
			// Second pass starts with the last slot of the first pass actually.
			for (uint32 slotCounter = 0; (slotCounter < slots * 2) && spentBytes < bytesToSpend; slotCounter++) {
				if (rememberedSlotCounter >= slots) {	// wrap around pointer
					rememberedSlotCounter = 0;
				}

				uint32 data = (slotCounter < slots - 1)	? doubleSendSize				// pass 1
															: (bytesToSpend - spentBytes);	// pass 2

				ThrottledFileSocket* socket = m_StandardOrder_list[ rememberedSlotCounter ];

				if (socket != NULL) {
					SocketSentBytes socketSentBytes = socket->SendFileAndControlData(data, doubleSendSize);
					spentBytes += socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
					spentOverhead += socketSentBytes.sentBytesControlPackets;
				} else {
					AddDebugLogLineN(logGeneral, CFormat(wxT("There was a NULL socket in the UploadBandwidthThrottler Standard list (equal-for-all)! Prevented usage. Index: %i Size: %i"))
						% rememberedSlotCounter % m_StandardOrder_list.size());
				}

				rememberedSlotCounter++;
			}

			// Do some limiting of what we keep for the next loop.
			bytesToSpend -= spentBytes;
			sint32 minBytesToSpend = (slots + 1) * minFragSize;

			if (bytesToSpend < - minBytesToSpend) {
				bytesToSpend = - minBytesToSpend;
			} else {
				sint32 bandwidthSavedTolerance = slots * 512 + 1;
				if (bytesToSpend > bandwidthSavedTolerance) {
					bytesToSpend = bandwidthSavedTolerance;
				}
			}
			
			m_SentBytesSinceLastCall += spentBytes;
			m_SentBytesSinceLastCallOverhead += spentOverhead;

			if (spentBytes == 0) {	// spentBytes includes the overhead
				extraSleepTime = std::min<uint32>(extraSleepTime * 5, 1000); // 1s at most
			} else {
				extraSleepTime = TIME_BETWEEN_UPLOAD_LOOPS;
			}
		}
	}

	{
		wxMutexLocker queueLock(m_tempQueueLocker);
		m_TempControlQueue_list.clear();
		m_TempControlQueueFirst_list.clear();
	}

	wxMutexLocker sendLock(m_sendLocker);
	m_ControlQueue_list.clear();
	m_StandardOrder_list.clear();

	return 0;
}
/**
 * The thread method that handles calling send for the individual sockets.
 *
 * Control packets will always be tried to be sent first. If there is any bandwidth leftover
 * after that, send() for the upload slot sockets will be called in priority order until we have run
 * out of available bandwidth for this loop. Upload slots will not be allowed to go without having sent
 * called for more than a defined amount of time (i.e. two seconds).
 *
 * @return always returns 0.
 */
UINT UploadBandwidthThrottler::RunInternal() {
    DWORD lastLoopTick = timeGetTime();
    sint64 realBytesToSpend = 0;
    uint32 allowedDataRate = 0;
    uint32 rememberedSlotCounter = 0;
    DWORD lastTickReachedBandwidth = timeGetTime();

    uint32 nEstiminatedLimit = 0;
    int nSlotsBusyLevel = 0;
    DWORD nUploadStartTime = 0;
    uint32 numberOfConsecutiveUpChanges = 0;
    uint32 numberOfConsecutiveDownChanges = 0;
    uint32 changesCount = 0;
    uint32 loopsCount = 0;

    bool estimateChangedLog = false;
    bool lotsOfLog = false;

    while(doRun) {
        pauseEvent->Lock();

        DWORD timeSinceLastLoop = timeGetTime() - lastLoopTick;

        // Get current speed from UploadSpeedSense
        allowedDataRate = theApp.lastCommonRouteFinder->GetUpload();

        // check busy level for all the slots (WSAEWOULDBLOCK status)
        uint32 cBusy = 0;
        uint32 nCanSend = 0;

        sendLocker.Lock();
        for (int i = 0; i < m_StandardOrder_list.GetSize() && (i < 3 || (UINT)i < GetSlotLimit(theApp.uploadqueue->GetDatarate())); i++) {
            if (m_StandardOrder_list[i] != NULL && m_StandardOrder_list[i]->HasQueues()) {
                nCanSend++;

                if(m_StandardOrder_list[i]->IsBusy())
                    cBusy++;
            }
        }
        sendLocker.Unlock();

        // if this is kept, the loop above can be a little optimized (don't count nCanSend, just use nCanSend = GetSlotLimit(theApp.uploadqueue->GetDatarate())
        if(theApp.uploadqueue)
            nCanSend = max(nCanSend, GetSlotLimit(theApp.uploadqueue->GetDatarate()));

        // When no upload limit has been set in options, try to guess a good upload limit.
        bool bUploadUnlimited = (thePrefs.GetMaxUpload() == UNLIMITED);
        if (bUploadUnlimited) {
            loopsCount++;

            //if(lotsOfLog) theApp.QueueDebugLogLine(false,_T("Throttler: busy: %i/%i nSlotsBusyLevel: %i Guessed limit: %0.5f changesCount: %i loopsCount: %i"), cBusy, nCanSend, nSlotsBusyLevel, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);

            if(nCanSend > 0) {
                float fBusyPercent = ((float)cBusy/(float)nCanSend) * 100;
                if (cBusy > 2 && fBusyPercent > 75.00f && nSlotsBusyLevel < 255) {
                    nSlotsBusyLevel++;
                    changesCount++;
                    if(thePrefs.GetVerbose() && lotsOfLog && nSlotsBusyLevel%25==0) theApp.QueueDebugLogLine(false,_T("Throttler: nSlotsBusyLevel: %i Guessed limit: %0.5f changesCount: %i loopsCount: %i"), nSlotsBusyLevel, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);
                }
                else if ( (cBusy <= 2 || fBusyPercent < 25.00f) && nSlotsBusyLevel > (-255)) {
                    nSlotsBusyLevel--;
                    changesCount++;
                    if(thePrefs.GetVerbose() && lotsOfLog && nSlotsBusyLevel%25==0) theApp.QueueDebugLogLine(false,_T("Throttler: nSlotsBusyLevel: %i Guessed limit: %0.5f changesCount %i loopsCount: %i"), nSlotsBusyLevel, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);
                }
            }

            if(nUploadStartTime == 0) {
                if (m_StandardOrder_list.GetSize() >= 3)
                    nUploadStartTime = timeGetTime();
            } else if(timeGetTime()- nUploadStartTime > SEC2MS(60)) {
                if (theApp.uploadqueue) {
                    if (nEstiminatedLimit == 0) { // no autolimit was set yet
                        if (nSlotsBusyLevel >= 250) { // sockets indicated that the BW limit has been reached
                            nEstiminatedLimit = theApp.uploadqueue->GetDatarate();
                            allowedDataRate = min(nEstiminatedLimit, allowedDataRate);
                            nSlotsBusyLevel = -200;
                            if(thePrefs.GetVerbose() && estimateChangedLog) theApp.QueueDebugLogLine(false,_T("Throttler: Set inital estimated limit to %0.5f changesCount: %i loopsCount: %i"), (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);
                            changesCount = 0;
                            loopsCount = 0;
                        }
                    }
                    else {
                        if (nSlotsBusyLevel > 250) {
                            if(changesCount > 500 || changesCount > 300 && loopsCount > 1000 || loopsCount > 2000) {
                                numberOfConsecutiveDownChanges = 0;
                            }
                            numberOfConsecutiveDownChanges++;
                            uint32 changeDelta = CalculateChangeDelta(numberOfConsecutiveDownChanges);

                            // Don't lower speed below 1 KBytes/s
                            if(nEstiminatedLimit < changeDelta + 1024) {
                                if(nEstiminatedLimit > 1024) {
                                    changeDelta = nEstiminatedLimit - 1024;
                                } else {
                                    changeDelta = 0;
                                }
                            }
                            ASSERT(nEstiminatedLimit >= changeDelta + 1024);
                            nEstiminatedLimit -= changeDelta;

                            if(thePrefs.GetVerbose() && estimateChangedLog) theApp.QueueDebugLogLine(false,_T("Throttler: REDUCED limit #%i with %i bytes to: %0.5f changesCount: %i loopsCount: %i"), numberOfConsecutiveDownChanges, changeDelta, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);

                            numberOfConsecutiveUpChanges = 0;
                            nSlotsBusyLevel = 0;
                            changesCount = 0;
                            loopsCount = 0;
                        }
                        else if (nSlotsBusyLevel < (-250)) {
                            if(changesCount > 500 || changesCount > 300 && loopsCount > 1000 || loopsCount > 2000) {
                                numberOfConsecutiveUpChanges = 0;
                            }
                            numberOfConsecutiveUpChanges++;
                            uint32 changeDelta = CalculateChangeDelta(numberOfConsecutiveUpChanges);

                            // Don't raise speed unless we are under current allowedDataRate
                            if(nEstiminatedLimit+changeDelta > allowedDataRate) {
                                if(nEstiminatedLimit < allowedDataRate) {
                                    changeDelta = allowedDataRate - nEstiminatedLimit;
                                } else {
                                    changeDelta = 0;
                                }
                            }
                            ASSERT(nEstiminatedLimit < allowedDataRate && nEstiminatedLimit+changeDelta <= allowedDataRate || nEstiminatedLimit >= allowedDataRate && changeDelta == 0);
                            nEstiminatedLimit += changeDelta;

                            if(thePrefs.GetVerbose() && estimateChangedLog) theApp.QueueDebugLogLine(false,_T("Throttler: INCREASED limit #%i with %i bytes to: %0.5f changesCount: %i loopsCount: %i"), numberOfConsecutiveUpChanges, changeDelta, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);

                            numberOfConsecutiveDownChanges = 0;
                            nSlotsBusyLevel = 0;
                            changesCount = 0;
                            loopsCount = 0;
                        }

                        allowedDataRate = min(nEstiminatedLimit, allowedDataRate);
                    }
                }
            }
        }

        if(cBusy == nCanSend && m_StandardOrder_list.GetSize() > 0) {
            allowedDataRate = 0;
            if(nSlotsBusyLevel < 125 && bUploadUnlimited) {
                nSlotsBusyLevel = 125;
                if(thePrefs.GetVerbose() && lotsOfLog) theApp.QueueDebugLogLine(false,_T("Throttler: nSlotsBusyLevel: %i Guessed limit: %0.5f changesCount %i loopsCount: %i (set due to all slots busy)"), nSlotsBusyLevel, (float)nEstiminatedLimit/1024.00f, changesCount, loopsCount);
            }
        }

        uint32 minFragSize = 1300;
        uint32 doubleSendSize = minFragSize*2; // send two packages at a time so they can share an ACK
        if(allowedDataRate < 6*1024) {
            minFragSize = 536;
            doubleSendSize = minFragSize; // don't send two packages at a time at very low speeds to give them a smoother load
        }

#define TIME_BETWEEN_UPLOAD_LOOPS 1
        uint32 sleepTime;
        if(allowedDataRate == _UI32_MAX || realBytesToSpend >= 1000 || allowedDataRate == 0 && nEstiminatedLimit == 0) {
            // we could send at once, but sleep a while to not suck up all cpu
            sleepTime = TIME_BETWEEN_UPLOAD_LOOPS;
        } else if(allowedDataRate == 0) {
            sleepTime = max((uint32)ceil(((double)doubleSendSize*1000)/nEstiminatedLimit), TIME_BETWEEN_UPLOAD_LOOPS);
        } else {
            // sleep for just as long as we need to get back to having one byte to send
            sleepTime = max((uint32)ceil((double)(-realBytesToSpend + 1000)/allowedDataRate), TIME_BETWEEN_UPLOAD_LOOPS);

        }

        if(timeSinceLastLoop < sleepTime) {
            Sleep(sleepTime-timeSinceLastLoop);
        }

        const DWORD thisLoopTick = timeGetTime();
        timeSinceLastLoop = thisLoopTick - lastLoopTick;

        // Calculate how many bytes we can spend
        sint64 bytesToSpend = 0;

        if(allowedDataRate != _UI32_MAX) {
            // prevent overflow
            if(timeSinceLastLoop == 0) {
                // no time has passed, so don't add any bytes. Shouldn't happen.
                bytesToSpend = 0; //realBytesToSpend/1000;
            } else if(_I64_MAX/timeSinceLastLoop > allowedDataRate && _I64_MAX-allowedDataRate*timeSinceLastLoop > realBytesToSpend) {
                if(timeSinceLastLoop > sleepTime + 2000) {
                    theApp.QueueDebugLogLine(false,_T("UploadBandwidthThrottler: Time since last loop too long. time: %ims wanted: %ims Max: %ims"), timeSinceLastLoop, sleepTime, sleepTime + 2000);

                    timeSinceLastLoop = sleepTime + 2000;
                    lastLoopTick = thisLoopTick - timeSinceLastLoop;
                }

                realBytesToSpend += allowedDataRate*timeSinceLastLoop;

                bytesToSpend = realBytesToSpend/1000;
            } else {
                realBytesToSpend = _I64_MAX;
                bytesToSpend = _I32_MAX;
            }
        } else {
            realBytesToSpend = 0; //_I64_MAX;
            bytesToSpend = _I32_MAX;
        }

        lastLoopTick = thisLoopTick;

        if(bytesToSpend >= 1 || allowedDataRate == 0) {
            uint64 spentBytes = 0;
            uint64 spentOverhead = 0;

            sendLocker.Lock();

            tempQueueLocker.Lock();

            // are there any sockets in m_TempControlQueue_list? Move them to normal m_ControlQueue_list;
            while(!m_TempControlQueueFirst_list.IsEmpty()) {
                ThrottledControlSocket* moveSocket = m_TempControlQueueFirst_list.RemoveHead();
                m_ControlQueueFirst_list.AddTail(moveSocket);
            }
            while(!m_TempControlQueue_list.IsEmpty()) {
                ThrottledControlSocket* moveSocket = m_TempControlQueue_list.RemoveHead();
                m_ControlQueue_list.AddTail(moveSocket);
            }

            tempQueueLocker.Unlock();

            // Send any queued up control packets first
            while((bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend || allowedDataRate == 0 && spentBytes < 500) && (!m_ControlQueueFirst_list.IsEmpty() || !m_ControlQueue_list.IsEmpty())) {
                ThrottledControlSocket* socket = NULL;

                if(!m_ControlQueueFirst_list.IsEmpty()) {
                    socket = m_ControlQueueFirst_list.RemoveHead();
                } else if(!m_ControlQueue_list.IsEmpty()) {
                    socket = m_ControlQueue_list.RemoveHead();
                }

                if(socket != NULL) {
                    SocketSentBytes socketSentBytes = socket->SendControlData(allowedDataRate > 0?(UINT)(bytesToSpend - spentBytes):1, minFragSize);
                    uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
                    spentBytes += lastSpentBytes;
                    spentOverhead += socketSentBytes.sentBytesControlPackets;
                }
            }

            // Check if any sockets haven't gotten data for a long time. Then trickle them a package.
            for(uint32 slotCounter = 0; slotCounter < (uint32)m_StandardOrder_list.GetSize(); slotCounter++) {
                ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(slotCounter);

                if(socket != NULL) {
                    if(thisLoopTick-socket->GetLastCalledSend() > SEC2MS(1)) {
                        // trickle
                        uint32 neededBytes = socket->GetNeededBytes();

                        if(neededBytes > 0) {
                            SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize);
                            uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
                            spentBytes += lastSpentBytes;
                            spentOverhead += socketSentBytes.sentBytesControlPackets;

                            if(lastSpentBytes > 0 && slotCounter < m_highestNumberOfFullyActivatedSlots) {
                                m_highestNumberOfFullyActivatedSlots = slotCounter;
                            }
                        }
                    }
                } else {
                    theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (trickle)! Prevented usage. Index: %i Size: %i"), slotCounter, m_StandardOrder_list.GetSize());
                }
            }

            // Equal bandwidth for all slots
            uint32 maxSlot = (uint32)m_StandardOrder_list.GetSize();
            if(maxSlot > 0 && allowedDataRate/maxSlot < UPLOAD_CLIENT_DATARATE) {
                maxSlot = allowedDataRate/UPLOAD_CLIENT_DATARATE;
            }

            if(maxSlot > m_highestNumberOfFullyActivatedSlots) {
                m_highestNumberOfFullyActivatedSlots = maxSlot;
            }

            for(uint32 maxCounter = 0; maxCounter < min(maxSlot, (uint32)m_StandardOrder_list.GetSize()) && bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend; maxCounter++) {
                if(rememberedSlotCounter >= (uint32)m_StandardOrder_list.GetSize() ||
                        rememberedSlotCounter >= maxSlot) {
                    rememberedSlotCounter = 0;
                }

                ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(rememberedSlotCounter);

                if(socket != NULL) {
                    SocketSentBytes socketSentBytes = socket->SendFileAndControlData((UINT)min(doubleSendSize, bytesToSpend-spentBytes), doubleSendSize);
                    uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;

                    spentBytes += lastSpentBytes;
                    spentOverhead += socketSentBytes.sentBytesControlPackets;
                } else {
                    theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (equal-for-all)! Prevented usage. Index: %i Size: %i"), rememberedSlotCounter, m_StandardOrder_list.GetSize());
                }

                rememberedSlotCounter++;
            }

            // Any bandwidth that hasn't been used yet are used first to last.
            for(uint32 slotCounter = 0; slotCounter < (uint32)m_StandardOrder_list.GetSize() && bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend; slotCounter++) {
                ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(slotCounter);

                if(socket != NULL) {
                    uint32 bytesToSpendTemp = (UINT)(bytesToSpend-spentBytes);
                    SocketSentBytes socketSentBytes = socket->SendFileAndControlData(bytesToSpendTemp, doubleSendSize);
                    uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;

                    spentBytes += lastSpentBytes;
                    spentOverhead += socketSentBytes.sentBytesControlPackets;

                    if(slotCounter+1 > m_highestNumberOfFullyActivatedSlots && (lastSpentBytes < bytesToSpendTemp || lastSpentBytes >= doubleSendSize)) { // || lastSpentBytes > 0 && spentBytes == bytesToSpend /*|| slotCounter+1 == (uint32)m_StandardOrder_list.GetSize())*/)) {
                        m_highestNumberOfFullyActivatedSlots = slotCounter+1;
                    }
                } else {
                    theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (fully activated)! Prevented usage. Index: %i Size: %i"), slotCounter, m_StandardOrder_list.GetSize());
                }
            }
            realBytesToSpend -= spentBytes*1000;

            // If we couldn't spend all allocated bandwidth this loop, some of it is allowed to be saved
            // and used the next loop
            if(realBytesToSpend < -(((sint64)m_StandardOrder_list.GetSize()+1)*minFragSize)*1000) {
                sint64 newRealBytesToSpend = -(((sint64)m_StandardOrder_list.GetSize()+1)*minFragSize)*1000;

                realBytesToSpend = newRealBytesToSpend;
                lastTickReachedBandwidth = thisLoopTick;
            } else {
                uint64 bandwidthSavedTolerance = 0;
                if(realBytesToSpend > 0 && (uint64)realBytesToSpend > 999+bandwidthSavedTolerance) {
                    sint64 newRealBytesToSpend = 999+bandwidthSavedTolerance;
                    //theApp.QueueDebugLogLine(false,_T("UploadBandwidthThrottler::RunInternal(): Too high saved bytesToSpend. Limiting value. Old value: %I64i New value: %I64i"), realBytesToSpend, newRealBytesToSpend);
                    realBytesToSpend = newRealBytesToSpend;

                    if(thisLoopTick-lastTickReachedBandwidth > max(1000, timeSinceLastLoop*2)) {
                        m_highestNumberOfFullyActivatedSlots = m_StandardOrder_list.GetSize()+1;
                        lastTickReachedBandwidth = thisLoopTick;
                        //theApp.QueueDebugLogLine(false, _T("UploadBandwidthThrottler: Throttler requests new slot due to bw not reached. m_highestNumberOfFullyActivatedSlots: %i m_StandardOrder_list.GetSize(): %i tick: %i"), m_highestNumberOfFullyActivatedSlots, m_StandardOrder_list.GetSize(), thisLoopTick);
                    }
                } else {
                    lastTickReachedBandwidth = thisLoopTick;
                }
            }

            // save info about how much bandwidth we've managed to use since the last time someone polled us about used bandwidth
            m_SentBytesSinceLastCall += spentBytes;
            m_SentBytesSinceLastCallOverhead += spentOverhead;

            sendLocker.Unlock();
        }
    }

    threadEndedEvent->SetEvent();

    tempQueueLocker.Lock();
    m_TempControlQueue_list.RemoveAll();
    m_TempControlQueueFirst_list.RemoveAll();
    tempQueueLocker.Unlock();

    sendLocker.Lock();

    m_ControlQueue_list.RemoveAll();
    m_StandardOrder_list.RemoveAll();
    sendLocker.Unlock();

    return 0;
}
/**
 * The thread method that handles calling send for the individual sockets.
 *
 * Control packets will always be tried to be sent first. If there is any bandwidth leftover
 * after that, send() for the upload slot sockets will be called in priority order until we have run
 * out of available bandwidth for this loop. Upload slots will not be allowed to go without having sent
 * called for more than a defined amount of time (i.e. two seconds).
 *
 * @return always returns 0.
 */
UINT UploadBandwidthThrottler::RunInternal() {

#define ADJUSTING_STEP	(1*1024)
    DWORD lastLoopTick = ::GetTickCount();
    sint64 realBytesToSpend = 0;
    uint32 allowedDataRate = 0;
    uint32 rememberedSlotCounter = 0;
    DWORD lastTickReachedBandwidth = ::GetTickCount();

// WebCache ////////////////////////////////////////////////////////////////////////////////////
    ////JP Proxy configuration testing START!!! This should probably be somewhere else.
    if (thePrefs.expectingWebCachePing && (::GetTickCount() - thePrefs.WebCachePingSendTime > SEC2MS(30)))
    {
        thePrefs.expectingWebCachePing = false;
        thePrefs.WebCacheDisabledThisSession = true; //Disable webcache downloads for the current proxy settings
        //JP we need a modeless dialogue here!!
//			AfxMessageBox(_T("Proxy configuration Test Failed please review your proxy-settings"));
        theApp.QueueLogLine(false, _T("Proxy configuration Test Failed please review your proxy-settings. Webcache downloads have been deactivated until emule is restarted."));
    }
    ////JP Proxy configuration testing END!!! This should probably be somewhere else.
    uint32 nEstiminatedLimit = 0;
    sint32 nSlotsBusyLevel = 0;
    DWORD nUploadStartTime = 0;
    bool bUploadUnlimited;

    while(doRun) {
        pauseEvent->Lock();

        DWORD timeSinceLastLoop = ::GetTickCount() - lastLoopTick;

        // Get current speed from UploadSpeedSense
        allowedDataRate = theApp.lastCommonRouteFinder->GetUpload();

        bUploadUnlimited = thePrefs.GetMaxUpload() == UNLIMITED;
        if (bUploadUnlimited && nUploadStartTime != 0 && ::GetTickCount()- nUploadStartTime > SEC2MS(60) ) { // upload is unlimited
            if (theApp.uploadqueue) {
                if (nEstiminatedLimit == 0) { // no autolimit was set yet
                    if (nSlotsBusyLevel >= 250) { // sockets indicated that the BW limit has been reached
                        nEstiminatedLimit = theApp.uploadqueue->GetDatarate() - (3*ADJUSTING_STEP);
                        allowedDataRate = min(nEstiminatedLimit, allowedDataRate);
                        nSlotsBusyLevel = -200;
                    }
                }
                else {
                    if (nSlotsBusyLevel > 250) {
                        nEstiminatedLimit -= ADJUSTING_STEP;
                        nSlotsBusyLevel = 0;

                    }
                    else if (nSlotsBusyLevel < (-250)) {
                        nEstiminatedLimit += ADJUSTING_STEP;
                        nSlotsBusyLevel = 0;
                    }
                    allowedDataRate = min(nEstiminatedLimit, allowedDataRate);
                }
            }
        }

        uint32 minFragSize = 1300;
        uint32 doubleSendSize = minFragSize*2; // send two packages at a time so they can share an ACK
        if(allowedDataRate < 6*1024) {
            minFragSize = 536;
            doubleSendSize = minFragSize; // don't send two packages at a time at very low speeds to give them a smoother load
        }

#define TIME_BETWEEN_UPLOAD_LOOPS 1
        uint32 sleepTime;
        if(allowedDataRate == 0 || allowedDataRate == _UI32_MAX || realBytesToSpend >= 1000) {
            // we could send at once, but sleep a while to not suck up all cpu
            sleepTime = TIME_BETWEEN_UPLOAD_LOOPS;
        } else {
            // sleep for just as long as we need to get back to having one byte to send
            sleepTime = max((uint32)ceil((double)(-realBytesToSpend + 1000)/allowedDataRate), TIME_BETWEEN_UPLOAD_LOOPS);

        }

        if(timeSinceLastLoop < sleepTime) {
            Sleep(sleepTime-timeSinceLastLoop);
        }

        const DWORD thisLoopTick = ::GetTickCount();
        timeSinceLastLoop = thisLoopTick - lastLoopTick;

        // Calculate how many bytes we can spend
        sint64 bytesToSpend = 0;

        if(allowedDataRate != 0 && allowedDataRate != _UI32_MAX) {
            // prevent overflow
            if(timeSinceLastLoop == 0) {
                // no time has passed, so don't add any bytes. Shouldn't happen.
                bytesToSpend = 0; //realBytesToSpend/1000;
            } else if(_I64_MAX/timeSinceLastLoop > allowedDataRate && _I64_MAX-allowedDataRate*timeSinceLastLoop > realBytesToSpend) {
                if(timeSinceLastLoop > sleepTime + 2000) {
                    theApp.QueueDebugLogLine(false,_T("UploadBandwidthThrottler: Time since last loop too long. time: %ims wanted: %ims Max: %ims"), timeSinceLastLoop, sleepTime, sleepTime + 2000);

                    timeSinceLastLoop = sleepTime + 2000;
                    lastLoopTick = thisLoopTick - timeSinceLastLoop;
                }

                realBytesToSpend += allowedDataRate*timeSinceLastLoop;

                bytesToSpend = realBytesToSpend/1000;
            } else {
                realBytesToSpend = _I64_MAX;
                bytesToSpend = _I32_MAX;
            }
        } else {
            realBytesToSpend = 0; //_I64_MAX;
            bytesToSpend = _I32_MAX;
        }

        lastLoopTick = thisLoopTick;

        if(bytesToSpend >= 1) {
            uint64 spentBytes = 0;
            uint64 spentOverhead = 0;

            sendLocker.Lock();

            tempQueueLocker.Lock();

            // are there any sockets in m_TempControlQueue_list? Move them to normal m_ControlQueue_list;
            while(!m_TempControlQueueFirst_list.IsEmpty()) {
                ThrottledControlSocket* moveSocket = m_TempControlQueueFirst_list.RemoveHead();
                m_ControlQueueFirst_list.AddTail(moveSocket);
            }
            while(!m_TempControlQueue_list.IsEmpty()) {
                ThrottledControlSocket* moveSocket = m_TempControlQueue_list.RemoveHead();
                m_ControlQueue_list.AddTail(moveSocket);
            }

            tempQueueLocker.Unlock();

            // Send any queued up control packets first
            while(bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend && (!m_ControlQueueFirst_list.IsEmpty() || !m_ControlQueue_list.IsEmpty())) {
                ThrottledControlSocket* socket = NULL;

                if(!m_ControlQueueFirst_list.IsEmpty()) {
                    socket = m_ControlQueueFirst_list.RemoveHead();
                } else if(!m_ControlQueue_list.IsEmpty()) {
                    socket = m_ControlQueue_list.RemoveHead();
                }

                if(socket != NULL) {
                    SocketSentBytes socketSentBytes = socket->SendControlData((UINT)(bytesToSpend - spentBytes), minFragSize);
                    uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
                    spentBytes += lastSpentBytes;
                    spentOverhead += socketSentBytes.sentBytesControlPackets;
                }
            }

            // Check if any sockets haven't gotten data for a long time. Then trickle them a package.
            for(uint32 slotCounter = 0; slotCounter < (uint32)m_StandardOrder_list.GetSize(); slotCounter++) {
                ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(slotCounter);

                if(socket != NULL) {
                    if(thisLoopTick-socket->GetLastCalledSend() > SEC2MS(1)) {
                        // trickle
                        uint32 neededBytes = socket->GetNeededBytes();

                        if(neededBytes > 0) {
                            SocketSentBytes socketSentBytes = socket->SendFileAndControlData(neededBytes, minFragSize);
                            uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;
                            spentBytes += lastSpentBytes;
                            spentOverhead += socketSentBytes.sentBytesControlPackets;

                            if(lastSpentBytes > 0 && slotCounter < m_highestNumberOfFullyActivatedSlots) {
                                m_highestNumberOfFullyActivatedSlots = slotCounter;
                            }
                        }
                    }
                } else {
                    theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (trickle)! Prevented usage. Index: %i Size: %i"), slotCounter, m_StandardOrder_list.GetSize());
                }
            }

            // Any bandwidth that hasn't been used yet are used first to last.
//Telp + Add Slot focus
            if((thePrefs.GetSlotFocus() == true)) {
                // Equal bandwidth for all slots
                uint32 maxSlot = (uint32)m_StandardOrder_list.GetSize();
                if(maxSlot > 0 && allowedDataRate/maxSlot < UPLOAD_CLIENT_DATARATE) {
                    maxSlot = allowedDataRate/UPLOAD_CLIENT_DATARATE;
                }

                if(maxSlot > m_highestNumberOfFullyActivatedSlots) {
                    m_highestNumberOfFullyActivatedSlots = maxSlot;
                }

                for(uint32 maxCounter = 0; maxCounter < min(maxSlot, (uint32)m_StandardOrder_list.GetSize()) && bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend; maxCounter++) {
                    if(rememberedSlotCounter >= (uint32)m_StandardOrder_list.GetSize() ||
                            rememberedSlotCounter >= maxSlot) {
                        rememberedSlotCounter = 0;
                    }

                    ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(rememberedSlotCounter);

                    if(socket != NULL) {
                        SocketSentBytes socketSentBytes = socket->SendFileAndControlData((UINT)min(doubleSendSize, bytesToSpend-spentBytes), doubleSendSize);
                        uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;

                        spentBytes += lastSpentBytes;
                        spentOverhead += socketSentBytes.sentBytesControlPackets;
                    } else {
                        theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (equal-for-all)! Prevented usage. Index: %i Size: %i"), rememberedSlotCounter, m_StandardOrder_list.GetSize());
                    }

                    rememberedSlotCounter++;
                }
                if (bUploadUnlimited) {
                    int cBusy = 0;
                    for (int i = 0; i < m_StandardOrder_list.GetSize(); i++) {
                        if (m_StandardOrder_list[i] != NULL && m_StandardOrder_list[i]->IsBusy())
                            cBusy++;
                    }
                    if (m_StandardOrder_list.GetSize() > 0) {
                        float fBusyPercent = ((float)cBusy/(float)m_StandardOrder_list.GetSize()) * 100;
                        if (cBusy > 2 && fBusyPercent > 75.00f && nSlotsBusyLevel < 255) {
                            nSlotsBusyLevel++;
                        }
                        else if ( (cBusy <= 2 || fBusyPercent < 25.00f) && nSlotsBusyLevel > (-255)) {
                            nSlotsBusyLevel--;
                        }
                        if (m_StandardOrder_list.GetSize() >= 3 && nUploadStartTime == 0)
                            nUploadStartTime = ::GetTickCount();
                    }
                }

                // Any bandwidth that hasn't been used yet are used first to last.
            }
            for(uint32 slotCounter = 0; slotCounter < (uint32)m_StandardOrder_list.GetSize() && bytesToSpend > 0 && spentBytes < (uint64)bytesToSpend; slotCounter++) {
                ThrottledFileSocket* socket = m_StandardOrder_list.GetAt(slotCounter);

                if(socket != NULL) {
                    uint32 bytesToSpendTemp = (UINT)(bytesToSpend-spentBytes);
                    SocketSentBytes socketSentBytes = socket->SendFileAndControlData(bytesToSpendTemp, doubleSendSize);
                    uint32 lastSpentBytes = socketSentBytes.sentBytesControlPackets + socketSentBytes.sentBytesStandardPackets;

                    spentBytes += lastSpentBytes;
                    spentOverhead += socketSentBytes.sentBytesControlPackets;

                    if(slotCounter+1 > m_highestNumberOfFullyActivatedSlots && (lastSpentBytes < bytesToSpendTemp || lastSpentBytes >= doubleSendSize)) { // || lastSpentBytes > 0 && spentBytes == bytesToSpend /*|| slotCounter+1 == (uint32)m_StandardOrder_list.GetSize())*/)) {
                        m_highestNumberOfFullyActivatedSlots = slotCounter+1;
                    }
                } else {
                    theApp.QueueDebugLogLine(false,_T("There was a NULL socket in the UploadBandwidthThrottler Standard list (fully activated)! Prevented usage. Index: %i Size: %i"), slotCounter, m_StandardOrder_list.GetSize());
                }
            }
            realBytesToSpend -= spentBytes*1000;

            if(realBytesToSpend < -(((sint64)m_StandardOrder_list.GetSize()+1)*minFragSize)*1000) {
                sint64 newRealBytesToSpend = -(((sint64)m_StandardOrder_list.GetSize()+1)*minFragSize)*1000;

                realBytesToSpend = newRealBytesToSpend;
                lastTickReachedBandwidth = thisLoopTick;
            } else {
                uint64 bandwidthSavedTolerance = m_StandardOrder_list.GetSize()*512*1000;
                if(realBytesToSpend > 0 && (uint64)realBytesToSpend > 999+bandwidthSavedTolerance) {
                    sint64 newRealBytesToSpend = 999+bandwidthSavedTolerance;
                    //theApp.QueueDebugLogLine(false,_T("UploadBandwidthThrottler::RunInternal(): Too high saved bytesToSpend. Limiting value. Old value: %I64i New value: %I64i"), realBytesToSpend, newRealBytesToSpend);
                    realBytesToSpend = newRealBytesToSpend;

                    if(thisLoopTick-lastTickReachedBandwidth > max(1000, timeSinceLastLoop*2)) {
                        m_highestNumberOfFullyActivatedSlots = m_StandardOrder_list.GetSize()+1;
                        lastTickReachedBandwidth = thisLoopTick;
                        //theApp.QueueDebugLogLine(false, _T("UploadBandwidthThrottler: Throttler requests new slot due to bw not reached. m_highestNumberOfFullyActivatedSlots: %i m_StandardOrder_list.GetSize(): %i tick: %i"), m_highestNumberOfFullyActivatedSlots, m_StandardOrder_list.GetSize(), thisLoopTick);
                    }
                } else {
                    lastTickReachedBandwidth = thisLoopTick;
                }
            }

            m_SentBytesSinceLastCall += spentBytes;
            m_SentBytesSinceLastCallOverhead += spentOverhead;

            sendLocker.Unlock();
        }
    }

    threadEndedEvent->SetEvent();

    tempQueueLocker.Lock();
    m_TempControlQueue_list.RemoveAll();
    m_TempControlQueueFirst_list.RemoveAll();
    tempQueueLocker.Unlock();

    sendLocker.Lock();

    m_ControlQueue_list.RemoveAll();
    m_StandardOrder_list.RemoveAll();
    sendLocker.Unlock();

    return 0;
}