aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs98
1 files changed, 70 insertions, 28 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 952d147..7d5c11e 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -96,6 +96,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 96
97 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 97 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
98 98
99 /// <summary>The measured resolution of Environment.TickCount</summary>
100 public readonly float TickCountResolution;
101
99 /// <summary>Handlers for incoming packets</summary> 102 /// <summary>Handlers for incoming packets</summary>
100 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 103 //PacketEventDictionary packetEvents = new PacketEventDictionary();
101 /// <summary>Incoming packets that are awaiting handling</summary> 104 /// <summary>Incoming packets that are awaiting handling</summary>
@@ -112,20 +115,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
112 private Scene m_scene; 115 private Scene m_scene;
113 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 116 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
114 private Location m_location; 117 private Location m_location;
115 /// <summary>The measured resolution of Environment.TickCount</summary>
116 private float m_tickCountResolution;
117 /// <summary>The size of the receive buffer for the UDP socket. This value 118 /// <summary>The size of the receive buffer for the UDP socket. This value
118 /// is passed up to the operating system and used in the system networking 119 /// is passed up to the operating system and used in the system networking
119 /// stack. Use zero to leave this value as the default</summary> 120 /// stack. Use zero to leave this value as the default</summary>
120 private int m_recvBufferSize; 121 private int m_recvBufferSize;
121 /// <summary>Flag to process packets asynchronously or synchronously</summary> 122 /// <summary>Flag to process packets asynchronously or synchronously</summary>
122 private bool m_asyncPacketHandling; 123 private bool m_asyncPacketHandling;
123 /// <summary>Track whether or not a packet was sent in the 124 /// <summary>Track the minimum amount of time needed to send the next packet in the
124 /// OutgoingPacketHandler loop so we know when to sleep</summary> 125 /// OutgoingPacketHandler loop so we know when to sleep</summary>
125 private bool m_packetSentLastLoop; 126 private int m_minTimeout = Int32.MaxValue;
127 /// <summary>EventWaitHandle to signify the outgoing packet handler thread that
128 /// there is more work to do</summary>
129 private EventWaitHandle m_outgoingWaitHandle;
126 130
127 /// <summary>The measured resolution of Environment.TickCount</summary>
128 public float TickCountResolution { get { return m_tickCountResolution; } }
129 public Socket Server { get { return null; } } 131 public Socket Server { get { return null; } }
130 132
131 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 133 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
@@ -134,16 +136,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
134 #region Environment.TickCount Measurement 136 #region Environment.TickCount Measurement
135 137
136 // Measure the resolution of Environment.TickCount 138 // Measure the resolution of Environment.TickCount
137 m_tickCountResolution = 0f; 139 TickCountResolution = 0f;
138 for (int i = 0; i < 5; i++) 140 for (int i = 0; i < 5; i++)
139 { 141 {
140 int start = Environment.TickCount; 142 int start = Environment.TickCount;
141 int now = start; 143 int now = start;
142 while (now == start) 144 while (now == start)
143 now = Environment.TickCount; 145 now = Environment.TickCount;
144 m_tickCountResolution += (float)(now - start) * 0.2f; 146 TickCountResolution += (float)(now - start) * 0.2f;
145 } 147 }
146 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); 148 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
149 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
147 150
148 #endregion Environment.TickCount Measurement 151 #endregion Environment.TickCount Measurement
149 152
@@ -171,6 +174,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
171 174
172 base.Start(m_recvBufferSize, m_asyncPacketHandling); 175 base.Start(m_recvBufferSize, m_asyncPacketHandling);
173 176
177 m_outgoingWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
178
174 // Start the incoming packet processing thread 179 // Start the incoming packet processing thread
175 Thread incomingThread = new Thread(IncomingPacketHandler); 180 Thread incomingThread = new Thread(IncomingPacketHandler);
176 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")"; 181 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")";
@@ -185,6 +190,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
185 { 190 {
186 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 191 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
187 base.Stop(); 192 base.Stop();
193
194 m_outgoingWaitHandle.Close();
188 } 195 }
189 196
190 public void AddScene(IScene scene) 197 public void AddScene(IScene scene)
@@ -768,6 +775,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
768 packetInbox.Clear(); 775 packetInbox.Clear();
769 } 776 }
770 777
778 public bool SignalOutgoingPacketHandler()
779 {
780 return m_outgoingWaitHandle.Set();
781 }
782
771 private void OutgoingPacketHandler() 783 private void OutgoingPacketHandler()
772 { 784 {
773 // Set this culture for the thread that outgoing packets are sent 785 // Set this culture for the thread that outgoing packets are sent
@@ -778,14 +790,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
778 { 790 {
779 try 791 try
780 { 792 {
781 m_packetSentLastLoop = false; 793 m_minTimeout = Int32.MaxValue;
782 794
795 // Handle outgoing packets, resends, acknowledgements, and pings for each
796 // client. m_minTimeout will be set to 0 if more packets are waiting in the
797 // queues with bandwidth to spare, or the number of milliseconds we need to
798 // wait before at least one packet can be sent to a client
783 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); 799 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
784 800
785 // If no packets at all were sent, sleep to avoid chewing up CPU cycles 801 // Can't wait for a negative amount of time, and put a 100ms ceiling on our
786 // when there is nothing to do 802 // maximum wait time
787 if (!m_packetSentLastLoop) 803 m_minTimeout = Utils.Clamp(m_minTimeout, 0, 100);
788 Thread.Sleep(20); 804
805 if (m_minTimeout > 0)
806 {
807 // Don't bother waiting for a shorter interval than our TickCountResolution
808 // since the token buckets wouldn't update anyways
809 m_minTimeout = Math.Max(m_minTimeout, (int)TickCountResolution);
810
811 // Wait for someone to signal that packets are ready to be sent, or for our
812 // sleep interval to expire
813 m_outgoingWaitHandle.WaitOne(m_minTimeout);
814 }
789 } 815 }
790 catch (Exception ex) 816 catch (Exception ex)
791 { 817 {
@@ -802,32 +828,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
802 { 828 {
803 LLUDPClient udpClient = ((LLClientView)client).UDPClient; 829 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
804 830
831 // Update ElapsedMSOutgoingPacketHandler
805 int thisTick = Environment.TickCount & Int32.MaxValue; 832 int thisTick = Environment.TickCount & Int32.MaxValue;
806 int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler; 833 if (udpClient.TickLastOutgoingPacketHandler > thisTick)
834 udpClient.ElapsedMSOutgoingPacketHandler += ((Int32.MaxValue - udpClient.TickLastOutgoingPacketHandler) + thisTick);
835 else
836 udpClient.ElapsedMSOutgoingPacketHandler += (thisTick - udpClient.TickLastOutgoingPacketHandler);
807 837
808 if (udpClient.IsConnected) 838 if (udpClient.IsConnected)
809 { 839 {
810 // Check for pending outgoing resends every 100ms 840 // Check for pending outgoing resends every 100ms
811 if (elapsedMS >= 100) 841 if (udpClient.ElapsedMSOutgoingPacketHandler >= 100)
812 { 842 {
813 ResendUnacked(udpClient); 843 ResendUnacked(udpClient);
844 udpClient.ElapsedMSOutgoingPacketHandler -= 100;
845 udpClient.Elapsed100MSOutgoingPacketHandler += 1;
846 }
814 847
815 // Check for pending outgoing ACKs every 500ms 848 // Check for pending outgoing ACKs every 500ms
816 if (elapsedMS >= 500) 849 if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5)
817 { 850 {
818 SendAcks(udpClient); 851 SendAcks(udpClient);
819 852 udpClient.Elapsed100MSOutgoingPacketHandler -= 5;
820 // Send pings to clients every 5000ms 853 udpClient.Elapsed500MSOutgoingPacketHandler += 1;
821 if (elapsedMS >= 5000) 854 }
822 { 855
823 SendPing(udpClient); 856 // Send pings to clients every 5000ms
824 } 857 if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10)
825 } 858 {
859 SendPing(udpClient);
860 udpClient.Elapsed500MSOutgoingPacketHandler -= 10;
826 } 861 }
827 862
828 // Dequeue any outgoing packets that are within the throttle limits 863 // Dequeue any outgoing packets that are within the throttle limits
829 if (udpClient.DequeueOutgoing()) 864 // and get the minimum time we would have to sleep before this client
830 m_packetSentLastLoop = true; 865 // could send a packet out
866 int minTimeoutThisLoop = udpClient.DequeueOutgoing();
867
868 // Although this is not thread safe, it is cheaper than locking and the
869 // worst that will happen is we sleep for slightly longer than the
870 // minimum necessary interval
871 if (minTimeoutThisLoop < m_minTimeout)
872 m_minTimeout = minTimeoutThisLoop;
831 } 873 }
832 874
833 udpClient.TickLastOutgoingPacketHandler = thisTick; 875 udpClient.TickLastOutgoingPacketHandler = thisTick;