Пример #1
0
		/// <summary>
		/// Check the usage of the CPU by this thread. If too much, do a balancing of the sockets.
		/// </summary>
		/// <param name="controlInformation"></param>
		private static void LoadBalancingTimer(ControlThreadInformation controlInformation, long now)
		{
			if (ProcessorsCount < 2 || controlInformation._rudpSockets.Count < 1)
				return;

			if ((now - controlInformation.LastCheckThreadCPUUsageTS) < CheckThreadCPUUsageInterval)
				return;

			lock (_loadBalancingSync)
			{
				//---- Calculate time spent
				long currentUsage = controlInformation.ProcessThread.TotalProcessorTime.Ticks;
				long spentTime = currentUsage - controlInformation.PreviousProcessorTime;
				controlInformation.PreviousProcessorTime = currentUsage;

				// Save it
				Thread.VolatileWrite(ref _controlThreadCPUUsages[controlInformation.ControlThreadId], spentTime);

				controlInformation.LastCheckThreadCPUUsageTS = now;

				long minUsage = Int32.MaxValue;
				long maxUsage = Int32.MinValue;
				int minIndex = -1;
				int maxIndex = -1;

				//---- Check for the min and max usage
				for (int index = 0; index < ProcessorsCount; index++)
				{
					if (_controlThreadCPUUsages[index] > maxUsage)
					{
						maxUsage = _controlThreadCPUUsages[index];
						maxIndex = index;
					}
					if (_controlThreadCPUUsages[index] < minUsage)
					{
						minUsage = _controlThreadCPUUsages[index];
						minIndex = index;
					}
				}

				//---- I use too much CPU compared to others
				float percent = 1.0f / 0.15f; // 15%
				if ((minUsage * percent) > maxUsage && maxIndex == controlInformation.ControlThreadId)
				{
					// Remove the socket from our list
					RUDPSocket balancingSocket = controlInformation._rudpSockets[0];
					controlInformation._rudpSockets.RemoveAt(0);

					// Put the socket in the new list
					_controlThreadInformations[minIndex]._rudpSocketsLock.EnterWriteLock();
					_controlThreadInformations[minIndex]._rudpSockets.Add(balancingSocket);
					_controlThreadInformations[minIndex]._rudpSocketsLock.ExitWriteLock();
					//System.Console.WriteLine("BALANCING");
				}
				//else System.Console.WriteLine("NO BALANCING");
			}
		}
Пример #2
0
		/// <summary>
		/// Set up a control thread to use the right CPU
		/// </summary>
		/// <param name="controlInformation"></param>
		private static void UpdateThreadAffinity(ControlThreadInformation controlInformation)
		{
			int id = AppDomain.GetCurrentThreadId();
			Process process = Process.GetCurrentProcess();

			foreach (ProcessThread processThread in process.Threads)
				if (processThread.Id == id)
				{
					controlInformation.ProcessThread = processThread;
					//processThread.IdealProcessor = processorAffinity;
					processThread.ProcessorAffinity = new IntPtr(controlInformation.ThreadAffinity);
				}
		}
Пример #3
0
		static RUDPStack()
		{
			AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);

			_isStackRunning = true;

			//---- Set to the maximum affinity
			UpdateAffinity();

			//---- Set up the control threads
			_controlThreadInformations = new ControlThreadInformation[ProcessorsCount];
			_controlThreadCPUUsages = new long[ProcessorsCount];
			int affinity = 1;
			for (int index = 0; index < ProcessorsCount; index++)
			{
				ControlThreadInformation info = new ControlThreadInformation();

				//---- Timers
				info.ThreadAffinity = affinity;
				info.ControlThreadId = index;
				info._protocolControlThread = new Thread(new ParameterizedThreadStart(ControlTimer));
				info._protocolControlThread.Name = "RUDP Control Timer - CPU(" + index + ")";
				info._protocolControlThread.IsBackground = true;
				info._protocolControlThread.Priority = ThreadPriority.Normal;

				_controlThreadInformations[index] = info;

				info._protocolControlThread.Start(info);

				affinity = affinity * 2;
			}
		}
Пример #4
0
		private static bool RetransmissionTimer(RUDPSocket rudp, long now, ControlThreadInformation controlInformation)
		{
			int count = rudp._outgoingPackets.Count;
			bool hasDoFastRetransmit = false;

			controlInformation._chargeCheckStopWatch.Reset();
			controlInformation._chargeCheckStopWatch.Start();
			for (int index = 0; index < count; index++)
			{
				rudp._outgoingPacketsLock.EnterReadLock();
				RUDPOutgoingPacket packet = rudp._outgoingPackets[index];
				rudp._outgoingPacketsLock.ExitReadLock();

				//---- Not yet sended
				if (packet.TSLastSend < 0)
					continue;

				//---- It is ACKed
				if (packet.IsACKed)
				{
					rudp._outgoingPacketsLock.EnterWriteLock();
					rudp._outgoingPackets.RemoveAt(index);
					rudp._outgoingPacketsLock.ExitWriteLock();

					ReleaseOutgoingPacket(packet);

					index--;
					count--;
					continue;
				}

				//---- Check for time out
				if (packet.TSFirstSend > -1 && (now - packet.TSFirstSend) > rudp._sto)
				{
					//-- Normal time out
					// Send connection Reset with ACK
					OnDisconnected(rudp, DisconnectionReason.TimeOut);
					return true;
				}

				//---- Retransmission or not ?
				bool fastRetransmit = (packet.PacketId >= rudp._fastRetransmitStartPacketId && packet.PacketId <= rudp._fastRetransmitEndPacketId);
				if (!fastRetransmit && (now - packet.TSLastSend) < rudp._rto)
					continue;

				hasDoFastRetransmit = hasDoFastRetransmit | fastRetransmit;

				//---- Get the SACK slots to send with
				SACKSlot slot1 = null, slot2 = null, slot3 = null, slot4 = null;
				rudp._sackWindow.GetSLACKSlots(out slot1, out slot2, out slot3, out slot4);

				// Update the payload for the SACK slots
				UpdatePacketPayload(packet.Payload, slot1, slot2, slot3, slot4);

#if CONSOLE_TRACE
				string acksList = "";
				if (slot1 != null)
					acksList += " [" + slot1.StartPacketId + " <-> " + slot1.EndPacketId + "]";
				if (slot2 != null)
					acksList += " [" + slot2.StartPacketId + " <-> " + slot2.EndPacketId + "]";
				if (slot3 != null)
					acksList += " [" + slot3.StartPacketId + " <-> " + slot3.EndPacketId + "]";
				if (slot4 != null)
					acksList += " [" + slot4.StartPacketId + " <-> " + slot4.EndPacketId + "]";
#endif

				// Send
#if CONSOLE_TRACE
				Trace("Resend packet(" + rudp.Handle + "): " + packet.PacketId + " RTO=" + rudp._rto + "RTT=" + rudp._rtt + " ACKs:" + acksList);
#endif
				if (SocketSendPacket(rudp, packet, packet.Payload, now))
				{
					rudp._controlWindow.OnTimeOut(packet);

					// Update
					packet.Retransmission++;
				}

				if (controlInformation._chargeCheckStopWatch.ElapsedMilliseconds > 0)
					return false;
			}

			//---- Reset fast retransmit
			if (hasDoFastRetransmit)
				rudp.OnEndFastRetransmit();

			return true;
		}
Пример #5
0
		/// <summary>
		/// Send all the fragments.
		/// </summary>
		/// <returns>True if all the fragments have been sent</returns>
		static private bool SendFragments(FragmentInformation fragments, ControlThreadInformation controlInformation)
		{
			controlInformation._chargeCheckStopWatch.Reset();
			controlInformation._chargeCheckStopWatch.Start();
			while (fragments.Size > 0)
			{
				//---- MSS : Full header (IP + UDP + RUDP)
				int MSS = fragments.rudp._mtu - (RUDPStack.UDPHeaderLength + RUDPStack.RUDPHeaderLength);

				int currentLength = Math.Min(MSS, fragments.Size);

				//---- If reliable, wait for the congestion windows
				if (fragments.IsReliable && !fragments.rudp._controlWindow.CanSend(currentLength))
					return false;

				//---- Send
				if (!PushPacketToSend(fragments.rudp,
									fragments.IsReliable,
									RUDPPacketChannel.UserPacket,
									fragments.Payload,
									fragments.Offset,
									currentLength))
				{
					fragments.Error = RUDPSocketError.SocketError;
					if (fragments.AsyncResult != null)
						OnSocketUnhandledError(fragments.rudp, fragments.Error, fragments.AsyncResult);
					return true;
				}

				fragments.Size -= currentLength;
				fragments.Offset += currentLength;

				//--- Avoid to block the Control thread, because sending a lot of fragments (allow to send ACKs too...)
				if (fragments.Size > 0 && controlInformation._chargeCheckStopWatch.ElapsedMilliseconds > 0)
					return false;
			}

			//---- End of send
			if (fragments.AsyncResult != null)
				fragments.rudp._physical.OnEndSend(fragments.rudp, fragments.AsyncResult);

			return true;
		}
Пример #6
0
		private static bool TransmissionTimer(RUDPSocket rudp, ControlThreadInformation controlInformation)
		{
			if (rudp._fragments.Count < 1)
				return true;

			rudp._fragmentsLock.EnterReadLock();
			FragmentInformation fragments = rudp._fragments.Last.Value;
			rudp._fragmentsLock.ExitReadLock();

			if (SendFragments(fragments, controlInformation))
			{
				rudp._fragmentsLock.EnterWriteLock();
				rudp._fragments.RemoveLast();
				rudp._fragmentsLock.ExitWriteLock();
				ReleaseFragmentInformation(fragments);
				return true;
			}

			// Else continue for other socket
			// will try to send packet during next loop
			ForceFragmentsSending(controlInformation.ControlThreadId);

			return false;
		}
Пример #7
0
		private static void ControlTimerProcessing(ControlThreadInformation controlInformation)
		{
			while (Thread.CurrentThread.IsAlive && _isStackRunning)
			{
				long now = HiResTimer.MicroSeconds;

				//---- Check load balancing
				LoadBalancingTimer(controlInformation, now);

				//---- Processing
				bool canResetEvent = true;
				for (int index = controlInformation._rudpSockets.Count - 1; index > -1; index--)
				{
					RUDPSocket rudp = controlInformation._rudpSockets[index];
					if (rudp._status == RUDPSocketStatus.Closed)
					{
						UnregisterRUDPSocket(rudp);
						continue;
					}

					//-- 0 - Transmission
					canResetEvent &= TransmissionTimer(rudp, controlInformation);

					//-- 1 - Send
					canResetEvent &= RetransmissionTimer(rudp, now, controlInformation);

					//-- 2 - ACKs
					ACKTimer(rudp, now);

					//-- 3 - Check for keep alive
					KeepAliveTimer(rudp, now);

					//-- 4 - MTU Discovery
					rudp._pmtuDiscovery.OnHeartBeat(now);

					//-- 5 - Bandwidth
					BandwidthTimer(rudp, now);
				}

				//---- Do not use 100%
				//Thread.Sleep(1);
				controlInformation._protocolControlEvent.WaitOne(1, true);
				if (canResetEvent)
					controlInformation._protocolControlEvent.Reset();
			}

		}