diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index e5b2594..b27d8d6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -80,7 +80,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 80 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
81 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 81 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 82 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
83 | public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); | 83 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); |
84 | 84 | ||
85 | /// <summary>Current packet sequence number</summary> | 85 | /// <summary>Current packet sequence number</summary> |
86 | public int CurrentSequence; | 86 | public int CurrentSequence; |
@@ -127,13 +127,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
127 | /// <summary>Throttle rate defaults and limits</summary> | 127 | /// <summary>Throttle rate defaults and limits</summary> |
128 | private readonly ThrottleRates defaultThrottleRates; | 128 | private readonly ThrottleRates defaultThrottleRates; |
129 | /// <summary>Outgoing queues for throttled packets</summary> | 129 | /// <summary>Outgoing queues for throttled packets</summary> |
130 | private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 130 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
131 | /// <summary>A container that can hold one packet for each outbox, used to store | 131 | /// <summary>A container that can hold one packet for each outbox, used to store |
132 | /// dequeued packets that are being held for throttling</summary> | 132 | /// dequeued packets that are being held for throttling</summary> |
133 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 133 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
134 | /// <summary>An optimization to store the length of dequeued packets being held | 134 | /// <summary>An optimization to store the length of dequeued packets being held |
135 | /// for throttling. This avoids expensive calls to Packet.Length</summary> | 135 | /// for throttling. This avoids expensive calls to Packet.Length</summary> |
136 | private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; | 136 | private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; |
137 | /// <summary>Flags to prevent queue empty callbacks from repeatedly firing | ||
138 | /// before the callbacks have a chance to put packets in the queue</summary> | ||
139 | private readonly bool[] queueEmptySent = new bool[THROTTLE_CATEGORY_COUNT]; | ||
137 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 140 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
138 | private readonly LLUDPServer udpServer; | 141 | private readonly LLUDPServer udpServer; |
139 | 142 | ||
@@ -156,7 +159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
156 | defaultThrottleRates = rates; | 159 | defaultThrottleRates = rates; |
157 | 160 | ||
158 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 161 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
159 | packetOutboxes[i] = new LocklessQueue<OutgoingPacket>(); | 162 | packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
160 | 163 | ||
161 | throttle = new TokenBucket(parentThrottle, 0, 0); | 164 | throttle = new TokenBucket(parentThrottle, 0, 0); |
162 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 165 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
@@ -182,6 +185,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
182 | public void Shutdown() | 185 | public void Shutdown() |
183 | { | 186 | { |
184 | IsConnected = false; | 187 | IsConnected = false; |
188 | NeedAcks.Clear(); | ||
189 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
190 | { | ||
191 | packetOutboxes[i].Clear(); | ||
192 | nextPackets[i] = null; | ||
193 | } | ||
194 | OnPacketStats = null; | ||
195 | OnQueueEmpty = null; | ||
185 | } | 196 | } |
186 | 197 | ||
187 | /// <summary> | 198 | /// <summary> |
@@ -322,7 +333,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
322 | 333 | ||
323 | if (category >= 0 && category < packetOutboxes.Length) | 334 | if (category >= 0 && category < packetOutboxes.Length) |
324 | { | 335 | { |
325 | LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; | 336 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; |
326 | TokenBucket bucket = throttleCategories[category]; | 337 | TokenBucket bucket = throttleCategories[category]; |
327 | 338 | ||
328 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) | 339 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) |
@@ -354,7 +365,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
354 | public bool DequeueOutgoing() | 365 | public bool DequeueOutgoing() |
355 | { | 366 | { |
356 | OutgoingPacket packet; | 367 | OutgoingPacket packet; |
357 | LocklessQueue<OutgoingPacket> queue; | 368 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; |
358 | TokenBucket bucket; | 369 | TokenBucket bucket; |
359 | bool packetSent = false; | 370 | bool packetSent = false; |
360 | 371 | ||
@@ -382,6 +393,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
382 | queue = packetOutboxes[i]; | 393 | queue = packetOutboxes[i]; |
383 | if (queue.Dequeue(out packet)) | 394 | if (queue.Dequeue(out packet)) |
384 | { | 395 | { |
396 | // Reset the flag for firing this queue's OnQueueEmpty callback | ||
397 | // now that we have dequeued a packet | ||
398 | queueEmptySent[i] = false; | ||
399 | |||
385 | // A packet was pulled off the queue. See if we have | 400 | // A packet was pulled off the queue. See if we have |
386 | // enough tokens in the bucket to send it out | 401 | // enough tokens in the bucket to send it out |
387 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | 402 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) |
@@ -397,13 +412,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
397 | nextPackets[i] = packet; | 412 | nextPackets[i] = packet; |
398 | nextPacketLengths[i] = packet.Buffer.DataLength; | 413 | nextPacketLengths[i] = packet.Buffer.DataLength; |
399 | } | 414 | } |
415 | |||
416 | // If the queue is empty after this dequeue, fire the queue | ||
417 | // empty callback now so it has a chance to fill before we | ||
418 | // get back here | ||
419 | if (queue.Count == 0) | ||
420 | FireQueueEmpty(i); | ||
400 | } | 421 | } |
401 | else | 422 | else |
402 | { | 423 | { |
403 | // No packets in this queue. Fire the queue empty callback | 424 | // No packets in this queue. Fire the queue empty callback |
404 | QueueEmpty callback = OnQueueEmpty; | 425 | // if it has not been called recently |
405 | if (callback != null) | 426 | FireQueueEmpty(i); |
406 | callback((ThrottleOutPacketType)i); | ||
407 | } | 427 | } |
408 | } | 428 | } |
409 | } | 429 | } |
@@ -432,8 +452,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
432 | 452 | ||
433 | // Always round retransmission timeout up to two seconds | 453 | // Always round retransmission timeout up to two seconds |
434 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); | 454 | RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); |
435 | //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + | 455 | //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + |
436 | // RTTVAR + " based on new RTT of " + r + "ms"); | 456 | // RTTVAR + " based on new RTT of " + r + "ms"); |
437 | } | 457 | } |
458 | |||
459 | private void FireQueueEmpty(int queueIndex) | ||
460 | { | ||
461 | if (!queueEmptySent[queueIndex]) | ||
462 | { | ||
463 | queueEmptySent[queueIndex] = true; | ||
464 | |||
465 | QueueEmpty callback = OnQueueEmpty; | ||
466 | if (callback != null) | ||
467 | Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex); | ||
468 | } | ||
469 | } | ||
438 | } | 470 | } |
439 | } | 471 | } |