diff options
author | Justin Clark-Casey (justincc) | 2011-11-11 22:37:57 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2011-11-11 22:37:57 +0000 |
commit | ce8441132e43dc8e3579f413daf914d48b8f115e (patch) | |
tree | b214c7999eb4f28389bc0e5963c05561d6734af1 /OpenSim/Region | |
parent | remove unncessary IClientAPI parameter from SP.SendSitResponse() (diff) | |
download | opensim-SC-ce8441132e43dc8e3579f413daf914d48b8f115e.zip opensim-SC-ce8441132e43dc8e3579f413daf914d48b8f115e.tar.gz opensim-SC-ce8441132e43dc8e3579f413daf914d48b8f115e.tar.bz2 opensim-SC-ce8441132e43dc8e3579f413daf914d48b8f115e.tar.xz |
Restore sending of OutPacket() for object kills removed in commit c7dd7b1.
OutPacket() must be called within the m_killRecord lock. Otherwise the following event sequence is possible
1) LLClientView.ProcessEntityUpdates() passes the kill record check for a particular part suspends before OutPacket()
2) Another thread calls LLClientView.SendKillObject() to delete the same part and modifies the kill record
3) The same thread places the kill packet on the Task queue.
4) The earlier thread resumes and places the update packet on the Task queue after the kill packet.
This results in a ghost part in the sim that only goes away after client relog.
This commit also removes the unnecessary m_entityUpdates.SyncRoot locking in SendKillObject.
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 46 |
1 files changed, 20 insertions, 26 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 4a0b0c6..626ebb5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -1546,41 +1546,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1546 | kill.Header.Reliable = true; | 1546 | kill.Header.Reliable = true; |
1547 | kill.Header.Zerocoded = true; | 1547 | kill.Header.Zerocoded = true; |
1548 | 1548 | ||
1549 | lock (m_killRecord) | 1549 | if (localIDs.Count == 1 && m_scene.GetScenePresence(localIDs[0]) != null) |
1550 | { | 1550 | { |
1551 | if (localIDs.Count == 1) | 1551 | OutPacket(kill, ThrottleOutPacketType.State); |
1552 | { | 1552 | } |
1553 | if (m_scene.GetScenePresence(localIDs[0]) != null) | 1553 | else |
1554 | { | 1554 | { |
1555 | OutPacket(kill, ThrottleOutPacketType.State); | 1555 | // We MUST lock for both manipulating the kill record and sending the packet, in order to avoid a race |
1556 | return; | 1556 | // condition where a kill can be processed before an out-of-date update for the same object. |
1557 | } | 1557 | // ProcessEntityUpdates() also takes the m_killRecord lock. |
1558 | m_killRecord.Add(localIDs[0]); | 1558 | lock (m_killRecord) |
1559 | } | ||
1560 | else | ||
1561 | { | 1559 | { |
1562 | lock (m_entityUpdates.SyncRoot) | 1560 | foreach (uint localID in localIDs) |
1563 | { | 1561 | m_killRecord.Add(localID); |
1564 | foreach (uint localID in localIDs) | 1562 | |
1565 | m_killRecord.Add(localID); | 1563 | // The throttle queue used here must match that being used for updates. Otherwise, there is a |
1566 | } | 1564 | // chance that a kill packet put on a separate queue will be sent to the client before an existing |
1565 | // update packet on another queue. Receiving updates after kills results in unowned and undeletable | ||
1566 | // scene objects in a viewer until that viewer is relogged in. | ||
1567 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1567 | } | 1568 | } |
1568 | } | 1569 | } |
1569 | |||
1570 | // The throttle queue used here must match that being used for | ||
1571 | // updates. Otherwise, there is a chance that a kill packet put | ||
1572 | // on a separate queue will be sent to the client before an | ||
1573 | // existing update packet on another queue. Receiving updates | ||
1574 | // after kills results in unowned and undeletable | ||
1575 | // scene objects in a viewer until that viewer is relogged in. | ||
1576 | OutPacket(kill, ThrottleOutPacketType.Task); | ||
1577 | } | 1570 | } |
1578 | 1571 | ||
1579 | /// <summary> | 1572 | /// <summary> |
1580 | /// Send information about the items contained in a folder to the client. | 1573 | /// Send information about the items contained in a folder to the client. |
1581 | /// | ||
1582 | /// XXX This method needs some refactoring loving | ||
1583 | /// </summary> | 1574 | /// </summary> |
1575 | /// <remarks> | ||
1576 | /// XXX This method needs some refactoring loving | ||
1577 | /// </remarks> | ||
1584 | /// <param name="ownerID">The owner of the folder</param> | 1578 | /// <param name="ownerID">The owner of the folder</param> |
1585 | /// <param name="folderID">The id of the folder</param> | 1579 | /// <param name="folderID">The id of the folder</param> |
1586 | /// <param name="items">The items contained in the folder identified by folderID</param> | 1580 | /// <param name="items">The items contained in the folder identified by folderID</param> |