* Increasing ScenePresences locking to prevent race conditions such as those seen in one of the crashes of mantis 1163

* It's not impossible that this could lead to deadlock where sessions simply appear to freeze, even though the region console still responds.
* If this is the case, please file a mantis
0.6.0-stable
Justin Clarke Casey 2008-05-07 22:59:30 +00:00
parent 95fbf63b3b
commit be02107ea8
3 changed files with 129 additions and 87 deletions

View File

@ -116,7 +116,11 @@ namespace OpenSim.Region.Environment.Scenes
public void Close() public void Close()
{ {
ScenePresences.Clear(); lock (ScenePresences)
{
ScenePresences.Clear();
}
//SceneObjects.Clear(); //SceneObjects.Clear();
Entities.Clear(); Entities.Clear();
} }
@ -792,6 +796,8 @@ namespace OpenSim.Region.Environment.Scenes
/// <returns></returns> /// <returns></returns>
public List<ScenePresence> GetScenePresences(FilterAvatarList filter) public List<ScenePresence> GetScenePresences(FilterAvatarList filter)
{ {
// No locking of scene presences here since we're passing back a list...
List<ScenePresence> result = new List<ScenePresence>(); List<ScenePresence> result = new List<ScenePresence>();
List<ScenePresence> ScenePresencesList = GetScenePresences(); List<ScenePresence> ScenePresencesList = GetScenePresences();
@ -813,9 +819,12 @@ namespace OpenSim.Region.Environment.Scenes
/// <returns>null if the agent was not found</returns> /// <returns>null if the agent was not found</returns>
public ScenePresence GetScenePresence(LLUUID agentID) public ScenePresence GetScenePresence(LLUUID agentID)
{ {
if (ScenePresences.ContainsKey(agentID)) lock (ScenePresences)
{ {
return ScenePresences[agentID]; if (ScenePresences.ContainsKey(agentID))
{
return ScenePresences[agentID];
}
} }
return null; return null;
@ -917,16 +926,19 @@ namespace OpenSim.Region.Environment.Scenes
internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
{ {
foreach (ScenePresence presence in ScenePresences.Values) lock (ScenePresences)
{ {
if (!presence.IsChildAgent) foreach (ScenePresence presence in ScenePresences.Values)
{ {
string name = presence.ControllingClient.FirstName + " " + presence.ControllingClient.LastName; if (!presence.IsChildAgent)
if (String.Compare(avatarName, name, true) == 0)
{ {
avatar = presence; string name = presence.ControllingClient.FirstName + " " + presence.ControllingClient.LastName;
return true;
if (String.Compare(avatarName, name, true) == 0)
{
avatar = presence;
return true;
}
} }
} }
} }
@ -1008,9 +1020,12 @@ namespace OpenSim.Region.Environment.Scenes
internal void ForEachClient(Action<IClientAPI> action) internal void ForEachClient(Action<IClientAPI> action)
{ {
foreach (ScenePresence presence in ScenePresences.Values) lock (ScenePresences)
{ {
action(presence.ControllingClient); foreach (ScenePresence presence in ScenePresences.Values)
{
action(presence.ControllingClient);
}
} }
} }

View File

@ -2076,18 +2076,21 @@ namespace OpenSim.Region.Environment.Scenes
{ {
if (regionHandle == m_regInfo.RegionHandle) if (regionHandle == m_regInfo.RegionHandle)
{ {
if (m_scenePresences.ContainsKey(agentID)) lock (m_scenePresences)
{ {
try if (m_scenePresences.ContainsKey(agentID))
{ {
m_scenePresences[agentID].MakeRootAgent(position, isFlying); try
{
m_scenePresences[agentID].MakeRootAgent(position, isFlying);
}
catch (Exception e)
{
m_log.Info("[SCENE]: Unable to do Agent Crossing.");
m_log.Debug("[SCENE]: " + e.ToString());
}
//m_innerScene.SwapRootChildAgent(false);
} }
catch (Exception e)
{
m_log.Info("[SCENE]: Unable to do Agent Crossing.");
m_log.Debug("[SCENE]: " + e.ToString());
}
//m_innerScene.SwapRootChildAgent(false);
} }
} }
} }
@ -2203,10 +2206,13 @@ namespace OpenSim.Region.Environment.Scenes
public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, LLVector3 position, public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, LLVector3 position,
LLVector3 lookAt, uint flags) LLVector3 lookAt, uint flags)
{ {
if (m_scenePresences.ContainsKey(remoteClient.AgentId)) lock (m_scenePresences)
{ {
m_sceneGridService.RequestTeleportToLocation(m_scenePresences[remoteClient.AgentId], regionHandle, if (m_scenePresences.ContainsKey(remoteClient.AgentId))
position, lookAt, flags); {
m_sceneGridService.RequestTeleportToLocation(m_scenePresences[remoteClient.AgentId], regionHandle,
position, lookAt, flags);
}
} }
} }
@ -2218,10 +2224,13 @@ namespace OpenSim.Region.Environment.Scenes
/// <param name="position"></param> /// <param name="position"></param>
public void RequestTeleportLandmark(IClientAPI remoteClient, ulong regionHandle, LLVector3 position) public void RequestTeleportLandmark(IClientAPI remoteClient, ulong regionHandle, LLVector3 position)
{ {
if (m_scenePresences.ContainsKey(remoteClient.AgentId)) lock (m_scenePresences)
{ {
m_sceneGridService.RequestTeleportToLocation(m_scenePresences[remoteClient.AgentId], regionHandle, if (m_scenePresences.ContainsKey(remoteClient.AgentId))
position, LLVector3.Zero, 0); {
m_sceneGridService.RequestTeleportToLocation(m_scenePresences[remoteClient.AgentId], regionHandle,
position, LLVector3.Zero, 0);
}
} }
} }
@ -2353,18 +2362,25 @@ namespace OpenSim.Region.Environment.Scenes
public void SendUrlToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, bool groupOwned, public void SendUrlToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, bool groupOwned,
string message, string url) string message, string url)
{ {
if (m_scenePresences.ContainsKey(avatarID)) lock (m_scenePresences)
{ {
m_scenePresences[avatarID].ControllingClient.SendLoadURL(objectName, objectID, ownerID, groupOwned, if (m_scenePresences.ContainsKey(avatarID))
message, url); {
m_scenePresences[avatarID].ControllingClient.SendLoadURL(objectName, objectID, ownerID, groupOwned,
message, url);
}
} }
} }
public void SendDialogToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, string message, LLUUID TextureID, int ch, string[] buttonlabels) public void SendDialogToUser(LLUUID avatarID, string objectName, LLUUID objectID, LLUUID ownerID, string message, LLUUID TextureID, int ch, string[] buttonlabels)
{ {
if (m_scenePresences.ContainsKey(avatarID)) lock (m_scenePresences)
{ {
m_scenePresences[avatarID].ControllingClient.SendDialog(objectName, objectID, ownerID, message, TextureID, ch, buttonlabels); if (m_scenePresences.ContainsKey(avatarID))
{
m_scenePresences[avatarID].ControllingClient.SendDialog(
objectName, objectID, ownerID, message, TextureID, ch, buttonlabels);
}
} }
} }
@ -2478,9 +2494,12 @@ namespace OpenSim.Region.Environment.Scenes
/// <param name="modal"></param> /// <param name="modal"></param>
public void SendAlertToUser(LLUUID agentID, string message, bool modal) public void SendAlertToUser(LLUUID agentID, string message, bool modal)
{ {
if (m_scenePresences.ContainsKey(agentID)) lock (m_scenePresences)
{ {
m_scenePresences[agentID].ControllingClient.SendAgentAlertMessage(message, modal); if (m_scenePresences.ContainsKey(agentID))
{
m_scenePresences[agentID].ControllingClient.SendAgentAlertMessage(message, modal);
}
} }
} }
@ -2494,28 +2513,31 @@ namespace OpenSim.Region.Environment.Scenes
public void handleRequestGodlikePowers(LLUUID agentID, LLUUID sessionID, LLUUID token, bool godLike, public void handleRequestGodlikePowers(LLUUID agentID, LLUUID sessionID, LLUUID token, bool godLike,
IClientAPI controllingClient) IClientAPI controllingClient)
{ {
// First check that this is the sim owner lock (m_scenePresences)
if (Permissions.GenericEstatePermission(agentID))
{ {
// User needs to be logged into this sim // User needs to be logged into this sim
if (m_scenePresences.ContainsKey(agentID)) if (m_scenePresences.ContainsKey(agentID))
{ {
// Next we check for spoofing..... // First check that this is the sim owner
LLUUID testSessionID = m_scenePresences[agentID].ControllingClient.SessionId; if (Permissions.GenericEstatePermission(agentID))
if (sessionID == testSessionID)
{ {
if (sessionID == controllingClient.SessionId) // Next we check for spoofing.....
LLUUID testSessionID = m_scenePresences[agentID].ControllingClient.SessionId;
if (sessionID == testSessionID)
{ {
//m_log.Info("godlike: " + godLike.ToString()); if (sessionID == controllingClient.SessionId)
m_scenePresences[agentID].GrantGodlikePowers(agentID, testSessionID, token, godLike); {
//m_log.Info("godlike: " + godLike.ToString());
m_scenePresences[agentID].GrantGodlikePowers(agentID, testSessionID, token, godLike);
}
} }
} }
else
{
m_scenePresences[agentID].ControllingClient.SendAgentAlertMessage("Request for god powers denied", false);
}
} }
} }
else
{
m_scenePresences[agentID].ControllingClient.SendAgentAlertMessage("Request for god powers denied", false);
}
} }
/// <summary> /// <summary>
@ -2571,55 +2593,59 @@ namespace OpenSim.Region.Environment.Scenes
{ {
// For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know. // For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know.
LLUUID kickUserID = new LLUUID("44e87126e7944ded05b37c42da3d5cdb"); LLUUID kickUserID = new LLUUID("44e87126e7944ded05b37c42da3d5cdb");
if (m_scenePresences.ContainsKey(agentID) || agentID == kickUserID) lock (m_scenePresences)
{ {
if (Permissions.GenericEstatePermission(godID)) if (m_scenePresences.ContainsKey(agentID) || agentID == kickUserID)
{ {
if (agentID == kickUserID) if (Permissions.GenericEstatePermission(godID))
{ {
ClientManager.ForEachClient(delegate(IClientAPI controller) if (agentID == kickUserID)
{
if (controller.AgentId != godID)
controller.Kick(Helpers.FieldToUTF8String(reason));
}
);
// This is a bit crude. It seems the client will be null before it actually stops the thread
// The thread will kill itself eventually :/
// Is there another way to make sure *all* clients get this 'inter region' message?
ClientManager.ForEachClient(delegate(IClientAPI controller)
{
ScenePresence p = GetScenePresence(controller.AgentId);
bool childagent = !p.Equals(null) && p.IsChildAgent;
if (controller.AgentId != godID && !childagent)
// Do we really want to kick the initiator of this madness?
{
controller.Close(true);
}
}
);
}
else
{
if (m_scenePresences[agentID].IsChildAgent)
{ {
m_innerScene.removeUserCount(false); ClientManager.ForEachClient(delegate(IClientAPI controller)
{
if (controller.AgentId != godID)
controller.Kick(Helpers.FieldToUTF8String(reason));
}
);
// This is a bit crude. It seems the client will be null before it actually stops the thread
// The thread will kill itself eventually :/
// Is there another way to make sure *all* clients get this 'inter region' message?
ClientManager.ForEachClient(delegate(IClientAPI controller)
{
ScenePresence p = GetScenePresence(controller.AgentId);
bool childagent = !p.Equals(null) && p.IsChildAgent;
if (controller.AgentId != godID && !childagent)
// Do we really want to kick the initiator of this madness?
{
controller.Close(true);
}
}
);
} }
else else
{ {
m_innerScene.removeUserCount(true); if (m_scenePresences[agentID].IsChildAgent)
} {
m_innerScene.removeUserCount(false);
}
else
{
m_innerScene.removeUserCount(true);
}
m_scenePresences[agentID].ControllingClient.Kick(Helpers.FieldToUTF8String(reason)); m_scenePresences[agentID].ControllingClient.Kick(Helpers.FieldToUTF8String(reason));
m_scenePresences[agentID].ControllingClient.Close(true); m_scenePresences[agentID].ControllingClient.Close(true);
}
}
else
{
if (m_scenePresences.ContainsKey(godID))
m_scenePresences[godID].ControllingClient.SendAgentAlertMessage("Kick request denied", false);
} }
}
else
{
if (m_scenePresences.ContainsKey(godID))
m_scenePresences[godID].ControllingClient.SendAgentAlertMessage("Kick request denied", false);
} }
} }
} }

View File

@ -1506,6 +1506,7 @@ namespace OpenSim.Region.Environment.Scenes
foreach (ScenePresence avatar in avatars) foreach (ScenePresence avatar in avatars)
{ {
SendFullUpdateToOtherClient(avatar); SendFullUpdateToOtherClient(avatar);
if (avatar.LocalId != LocalId) if (avatar.LocalId != LocalId)
{ {
if (!avatar.m_isChildAgent || m_scene.m_seeIntoRegionFromNeighbor) if (!avatar.m_isChildAgent || m_scene.m_seeIntoRegionFromNeighbor)