diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 98 |
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; |