diff options
author | Dan Lake | 2010-03-17 06:40:00 -0700 |
---|---|---|
committer | John Hurliman | 2010-03-17 11:21:27 -0700 |
commit | 73e9b0be725a73a489b29f3fe2df236c897ef3b5 (patch) | |
tree | 0d039d61d327e98ed22e4bce30de65c24fc5780d /OpenSim/Region/Framework/Scenes/SceneGraph.cs | |
parent | minor logging changes to BaseHttpServer, OSHttpRequest (diff) | |
download | opensim-SC-73e9b0be725a73a489b29f3fe2df236c897ef3b5.zip opensim-SC-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.gz opensim-SC-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.bz2 opensim-SC-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.xz |
Inconsistent locking of ScenePresence array in SceneGraph. Fixed by eliminating option to return the actual list. Callers can now either request a copy of the array as a new List or ask the SceneGraph to call a delegate function on every ScenePresence. Iteration and locking of the ScenePresences now takes place only within the SceneGraph class.
This patch also applies a fix to Combat/CombatModule.cs which had unlocked iteration of the ScenePresences and inconsistent try/catch around the use of those ScenePresences.
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 193 |
1 files changed, 130 insertions, 63 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index d944834..d259c42 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -165,9 +165,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
165 | 165 | ||
166 | protected internal void UpdatePresences() | 166 | protected internal void UpdatePresences() |
167 | { | 167 | { |
168 | ScenePresence[] updateScenePresences = GetScenePresences(); | 168 | ForEachScenePresence(delegate(ScenePresence presence) |
169 | for (int i = 0; i < updateScenePresences.Length; i++) | 169 | { |
170 | updateScenePresences[i].Update(); | 170 | presence.Update(); |
171 | }); | ||
171 | } | 172 | } |
172 | 173 | ||
173 | protected internal float UpdatePhysics(double elapsed) | 174 | protected internal float UpdatePhysics(double elapsed) |
@@ -196,9 +197,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
196 | 197 | ||
197 | protected internal void UpdateScenePresenceMovement() | 198 | protected internal void UpdateScenePresenceMovement() |
198 | { | 199 | { |
199 | ScenePresence[] moveEntities = GetScenePresences(); | 200 | ForEachScenePresence(delegate(ScenePresence presence) |
200 | for (int i = 0; i < moveEntities.Length; i++) | 201 | { |
201 | moveEntities[i].UpdateMovement(); | 202 | presence.UpdateMovement(); |
203 | }); | ||
202 | } | 204 | } |
203 | 205 | ||
204 | #endregion | 206 | #endregion |
@@ -616,18 +618,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
616 | 618 | ||
617 | public void RecalculateStats() | 619 | public void RecalculateStats() |
618 | { | 620 | { |
619 | ScenePresence[] presences = GetScenePresences(); | ||
620 | int rootcount = 0; | 621 | int rootcount = 0; |
621 | int childcount = 0; | 622 | int childcount = 0; |
622 | 623 | ||
623 | for (int i = 0; i < presences.Length; i++) | 624 | ForEachScenePresence(delegate(ScenePresence presence) |
624 | { | 625 | { |
625 | ScenePresence user = presences[i]; | 626 | if (presence.IsChildAgent) |
626 | if (user.IsChildAgent) | ||
627 | ++childcount; | 627 | ++childcount; |
628 | else | 628 | else |
629 | ++rootcount; | 629 | ++rootcount; |
630 | } | 630 | }); |
631 | 631 | ||
632 | m_numRootAgents = rootcount; | 632 | m_numRootAgents = rootcount; |
633 | m_numChildAgents = childcount; | 633 | m_numChildAgents = childcount; |
@@ -674,25 +674,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
674 | #endregion | 674 | #endregion |
675 | 675 | ||
676 | #region Get Methods | 676 | #region Get Methods |
677 | |||
678 | /// <summary> | ||
679 | /// Request a List of all scene presences in this scene. This is a new list, so no | ||
680 | /// locking is required to iterate over it. | ||
681 | /// </summary> | ||
682 | /// <returns></returns> | ||
683 | protected internal ScenePresence[] GetScenePresences() | ||
684 | { | ||
685 | return m_scenePresenceArray; | ||
686 | } | ||
687 | |||
688 | protected internal List<ScenePresence> GetAvatars() | ||
689 | { | ||
690 | List<ScenePresence> result = | ||
691 | GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; }); | ||
692 | |||
693 | return result; | ||
694 | } | ||
695 | |||
696 | /// <summary> | 677 | /// <summary> |
697 | /// Get the controlling client for the given avatar, if there is one. | 678 | /// Get the controlling client for the given avatar, if there is one. |
698 | /// | 679 | /// |
@@ -718,45 +699,119 @@ namespace OpenSim.Region.Framework.Scenes | |||
718 | return null; | 699 | return null; |
719 | } | 700 | } |
720 | 701 | ||
702 | // The idea is to have a group of method that return a list of avatars meeting some requirement | ||
703 | // ie it could be all m_scenePresences within a certain range of the calling prim/avatar. | ||
704 | // | ||
705 | // GetAvatars returns a new list of all root agent presences in the scene | ||
706 | // GetScenePresences returns a new list of all presences in the scene or a filter may be passed. | ||
707 | // GetScenePresence returns the presence with matching UUID or the first presence matching the passed filter. | ||
708 | // ForEachScenePresence requests the Scene to run a delegate function against all presences. | ||
709 | |||
710 | /// <summary> | ||
711 | /// Request a list of all avatars in this region (no child agents) | ||
712 | /// This list is a new object, so it can be iterated over without locking. | ||
713 | /// </summary> | ||
714 | /// <returns></returns> | ||
715 | public List<ScenePresence> GetAvatars() | ||
716 | { | ||
717 | return GetScenePresences(delegate(ScenePresence scenePresence) | ||
718 | { | ||
719 | return !scenePresence.IsChildAgent; | ||
720 | }); | ||
721 | } | ||
722 | |||
723 | /// <summary> | ||
724 | /// Request a list of m_scenePresences in this World | ||
725 | /// Returns a copy so it can be iterated without a lock. | ||
726 | /// There is no guarantee that presences will remain in the scene after the list is returned. | ||
727 | /// </summary> | ||
728 | /// <returns></returns> | ||
729 | protected internal List<ScenePresence> GetScenePresences() | ||
730 | { | ||
731 | List<ScenePresence> result; | ||
732 | lock (m_scenePresences) | ||
733 | { | ||
734 | result = new List<ScenePresence>(m_scenePresenceArray.Length); | ||
735 | result.AddRange(m_scenePresenceArray); | ||
736 | } | ||
737 | return result; | ||
738 | } | ||
739 | |||
721 | /// <summary> | 740 | /// <summary> |
722 | /// Request a filtered list of m_scenePresences in this World | 741 | /// Request a filtered list of m_scenePresences in this World |
742 | /// Returns a copy so it can be iterated without a lock. | ||
743 | /// There is no guarantee that presences will remain in the scene after the list is returned. | ||
723 | /// </summary> | 744 | /// </summary> |
724 | /// <returns></returns> | 745 | /// <returns></returns> |
725 | protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter) | 746 | protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter) |
726 | { | 747 | { |
727 | // No locking of scene presences here since we're passing back a list... | ||
728 | |||
729 | List<ScenePresence> result = new List<ScenePresence>(); | 748 | List<ScenePresence> result = new List<ScenePresence>(); |
730 | ScenePresence[] scenePresences = GetScenePresences(); | 749 | // Check each ScenePresence against the filter |
750 | ForEachScenePresence(delegate(ScenePresence presence) | ||
751 | { | ||
752 | if (filter(presence)) | ||
753 | result.Add(presence); | ||
754 | }); | ||
755 | return result; | ||
756 | } | ||
731 | 757 | ||
732 | for (int i = 0; i < scenePresences.Length; i++) | 758 | /// <summary> |
759 | /// Request the ScenePresence in this region matching filter. | ||
760 | /// Only the first match is returned. | ||
761 | /// | ||
762 | /// </summary> | ||
763 | /// <param name="filter"></param> | ||
764 | /// <returns></returns> | ||
765 | protected internal ScenePresence GetScenePresence(FilterAvatarList filter) | ||
766 | { | ||
767 | ScenePresence result = null; | ||
768 | // Get all of the ScenePresences | ||
769 | List<ScenePresence> presences = GetScenePresences(); | ||
770 | foreach (ScenePresence presence in presences) | ||
733 | { | 771 | { |
734 | ScenePresence avatar = scenePresences[i]; | 772 | if (filter(presence)) |
735 | if (filter(avatar)) | 773 | { |
736 | result.Add(avatar); | 774 | result = presence; |
775 | break; | ||
776 | } | ||
737 | } | 777 | } |
738 | |||
739 | return result; | 778 | return result; |
740 | } | 779 | } |
741 | 780 | ||
781 | protected internal ScenePresence GetScenePresence(string firstName, string lastName) | ||
782 | { | ||
783 | return GetScenePresence(delegate(ScenePresence presence) | ||
784 | { | ||
785 | return(presence.Firstname == firstName && presence.Lastname == lastName); | ||
786 | }); | ||
787 | } | ||
788 | |||
742 | /// <summary> | 789 | /// <summary> |
743 | /// Request a scene presence by UUID | 790 | /// Request a scene presence by UUID |
744 | /// </summary> | 791 | /// </summary> |
745 | /// <param name="avatarID"></param> | 792 | /// <param name="agentID"></param> |
746 | /// <returns>null if the agent was not found</returns> | 793 | /// <returns>null if the agent was not found</returns> |
747 | protected internal ScenePresence GetScenePresence(UUID agentID) | 794 | protected internal ScenePresence GetScenePresence(UUID agentID) |
748 | { | 795 | { |
749 | ScenePresence sp; | 796 | ScenePresence sp; |
750 | 797 | TryGetAvatar(agentID, out sp); | |
751 | lock (m_scenePresences) | ||
752 | { | ||
753 | m_scenePresences.TryGetValue(agentID, out sp); | ||
754 | } | ||
755 | |||
756 | return sp; | 798 | return sp; |
757 | } | 799 | } |
758 | 800 | ||
759 | /// <summary> | 801 | /// <summary> |
802 | /// Request the ScenePresence in this region by localID. | ||
803 | /// </summary> | ||
804 | /// <param name="localID"></param> | ||
805 | /// <returns></returns> | ||
806 | protected internal ScenePresence GetScenePresence(uint localID) | ||
807 | { | ||
808 | return GetScenePresence(delegate(ScenePresence presence) | ||
809 | { | ||
810 | return (presence.LocalId == localID); | ||
811 | }); | ||
812 | } | ||
813 | |||
814 | /// <summary> | ||
760 | /// Get a scene object group that contains the prim with the given local id | 815 | /// Get a scene object group that contains the prim with the given local id |
761 | /// </summary> | 816 | /// </summary> |
762 | /// <param name="localID"></param> | 817 | /// <param name="localID"></param> |
@@ -910,29 +965,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
910 | protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) | 965 | protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) |
911 | { | 966 | { |
912 | lock (m_scenePresences) | 967 | lock (m_scenePresences) |
913 | return m_scenePresences.TryGetValue(avatarId, out avatar); | 968 | { |
969 | m_scenePresences.TryGetValue(avatarId, out avatar); | ||
970 | } | ||
971 | return (avatar != null); | ||
914 | } | 972 | } |
915 | 973 | ||
916 | protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) | 974 | protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) |
917 | { | 975 | { |
918 | ScenePresence[] presences = GetScenePresences(); | 976 | avatar = GetScenePresence(delegate(ScenePresence presence) |
919 | |||
920 | for (int i = 0; i < presences.Length; i++) | ||
921 | { | 977 | { |
922 | ScenePresence presence = presences[i]; | 978 | return (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0); |
923 | 979 | }); | |
924 | if (!presence.IsChildAgent) | 980 | return (avatar != null); |
925 | { | ||
926 | if (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0) | ||
927 | { | ||
928 | avatar = presence; | ||
929 | return true; | ||
930 | } | ||
931 | } | ||
932 | } | ||
933 | |||
934 | avatar = null; | ||
935 | return false; | ||
936 | } | 981 | } |
937 | 982 | ||
938 | /// <summary> | 983 | /// <summary> |
@@ -1013,6 +1058,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
1013 | } | 1058 | } |
1014 | } | 1059 | } |
1015 | } | 1060 | } |
1061 | |||
1062 | |||
1063 | /// <summary> | ||
1064 | /// Performs action on all scene presences. | ||
1065 | /// </summary> | ||
1066 | /// <param name="action"></param> | ||
1067 | public void ForEachScenePresence(Action<ScenePresence> action) | ||
1068 | { | ||
1069 | List<ScenePresence> presences = GetScenePresences(); | ||
1070 | try | ||
1071 | { | ||
1072 | foreach(ScenePresence presence in presences) | ||
1073 | { | ||
1074 | action(presence); | ||
1075 | } | ||
1076 | } | ||
1077 | catch (Exception e) | ||
1078 | { | ||
1079 | m_log.Info("[BUG] in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString()); | ||
1080 | m_log.Info("[BUG] Stack Trace: " + e.StackTrace); | ||
1081 | } | ||
1082 | } | ||
1016 | 1083 | ||
1017 | #endregion | 1084 | #endregion |
1018 | 1085 | ||