Convert multiple lock()s which directly hinder script performance in linksets to ReaderWriterLockSlim.

avinationmerge
CasperW 2009-11-27 18:29:03 +01:00
parent 8bbb88ea4e
commit 9888f95068
3 changed files with 541 additions and 305 deletions

View File

@ -98,6 +98,66 @@ namespace OpenSim.Region.Framework.Scenes
private bool m_hasGroupChanged = false; private bool m_hasGroupChanged = false;
private long timeFirstChanged; private long timeFirstChanged;
private long timeLastChanged; private long timeLastChanged;
private System.Threading.ReaderWriterLockSlim m_partsLock = new System.Threading.ReaderWriterLockSlim();
public void lockPartsForRead(bool locked)
{
if (locked)
{
if (m_partsLock.RecursiveReadCount > 0)
{
m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
m_partsLock.ExitReadLock();
}
if (m_partsLock.RecursiveWriteCount > 0)
{
m_log.Error("[SceneObjectGroup.m_parts] Recursive read lock requested. This should not happen and means something needs to be fixed.");
m_partsLock.ExitWriteLock();
}
while (!m_partsLock.TryEnterReadLock(60000))
{
m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire READ lock of m_parts in SceneObjectGroup. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
if (m_partsLock.IsWriteLockHeld)
{
m_partsLock = new System.Threading.ReaderWriterLockSlim();
}
}
}
else
{
m_partsLock.ExitReadLock();
}
}
public void lockPartsForWrite(bool locked)
{
if (locked)
{
if (m_partsLock.RecursiveReadCount > 0)
{
m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
m_partsLock.ExitReadLock();
}
if (m_partsLock.RecursiveWriteCount > 0)
{
m_log.Error("[SceneObjectGroup.m_parts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
m_partsLock.ExitWriteLock();
}
while (!m_partsLock.TryEnterWriteLock(60000))
{
m_log.Error("[SceneObjectGroup.m_parts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
if (m_partsLock.IsWriteLockHeld)
{
m_partsLock = new System.Threading.ReaderWriterLockSlim();
}
}
}
else
{
m_partsLock.ExitWriteLock();
}
}
public bool HasGroupChanged public bool HasGroupChanged
{ {
@ -243,13 +303,16 @@ namespace OpenSim.Region.Framework.Scenes
set set
{ {
m_regionHandle = value; m_regionHandle = value;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.RegionHandle = m_regionHandle; part.RegionHandle = m_regionHandle;
} }
} }
lockPartsForRead(false);
} }
} }
@ -275,13 +338,16 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.CrossPrimGroupIntoNewRegion(val, this, true); m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
} }
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.GroupPosition = val; part.GroupPosition = val;
} }
} }
lockPartsForRead(false);
//if (m_rootPart.PhysActor != null) //if (m_rootPart.PhysActor != null)
//{ //{
@ -432,13 +498,16 @@ namespace OpenSim.Region.Framework.Scenes
public void SetFromItemID(UUID AssetId) public void SetFromItemID(UUID AssetId)
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.FromItemID = AssetId; part.FromItemID = AssetId;
} }
} }
lockPartsForRead(false);
} }
public UUID GetFromItemID() public UUID GetFromItemID()
@ -505,10 +574,11 @@ namespace OpenSim.Region.Framework.Scenes
Vector3 maxScale = Vector3.Zero; Vector3 maxScale = Vector3.Zero;
Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
Vector3 partscale = part.Scale; Vector3 partscale = part.Scale;
Vector3 partoffset = part.OffsetPosition; Vector3 partoffset = part.OffsetPosition;
@ -519,8 +589,11 @@ namespace OpenSim.Region.Framework.Scenes
maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
} }
} }
lockPartsForRead(false);
finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
@ -536,10 +609,11 @@ namespace OpenSim.Region.Framework.Scenes
EntityIntersection result = new EntityIntersection(); EntityIntersection result = new EntityIntersection();
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
// Temporary commented to stop compiler warning // Temporary commented to stop compiler warning
//Vector3 partPosition = //Vector3 partPosition =
// new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z); // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
@ -567,8 +641,10 @@ namespace OpenSim.Region.Framework.Scenes
result.distance = inter.distance; result.distance = inter.distance;
} }
} }
} }
} }
lockPartsForRead(false);
return result; return result;
} }
@ -581,10 +657,11 @@ namespace OpenSim.Region.Framework.Scenes
public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight) public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
{ {
float maxX = -256f, maxY = -256f, maxZ = -256f, minX = 256f, minY = 256f, minZ = 256f; float maxX = -256f, maxY = -256f, maxZ = -256f, minX = 256f, minY = 256f, minZ = 256f;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
Vector3 worldPos = part.GetWorldPosition(); Vector3 worldPos = part.GetWorldPosition();
Vector3 offset = worldPos - AbsolutePosition; Vector3 offset = worldPos - AbsolutePosition;
Quaternion worldRot; Quaternion worldRot;
@ -643,6 +720,8 @@ namespace OpenSim.Region.Framework.Scenes
backBottomRight.Y = orig.Y + (part.Scale.Y / 2); backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
backBottomRight.Z = orig.Z - (part.Scale.Z / 2); backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
//m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
//m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
//m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
@ -814,6 +893,7 @@ namespace OpenSim.Region.Framework.Scenes
minZ = backBottomLeft.Z; minZ = backBottomLeft.Z;
} }
} }
lockPartsForRead(false);
Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ); Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
@ -842,17 +922,20 @@ namespace OpenSim.Region.Framework.Scenes
Dictionary<UUID,string> states = new Dictionary<UUID,string>(); Dictionary<UUID,string> states = new Dictionary<UUID,string>();
// Capture script state while holding the lock // Capture script state while holding the lock
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates(); Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates();
foreach (UUID itemid in pstates.Keys) foreach (UUID itemid in pstates.Keys)
{ {
states.Add(itemid, pstates[itemid]); states.Add(itemid, pstates[itemid]);
} }
} }
} }
lockPartsForRead(false);
if (states.Count > 0) if (states.Count > 0)
{ {
@ -1014,13 +1097,16 @@ namespace OpenSim.Region.Framework.Scenes
public override void UpdateMovement() public override void UpdateMovement()
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.UpdateMovement(); part.UpdateMovement();
} }
} }
lockPartsForRead(false);
} }
public ushort GetTimeDilation() public ushort GetTimeDilation()
@ -1064,7 +1150,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="part"></param> /// <param name="part"></param>
public void AddPart(SceneObjectPart part) public void AddPart(SceneObjectPart part)
{ {
lock (m_parts) lockPartsForWrite(true);
{ {
part.SetParent(this); part.SetParent(this);
m_parts.Add(part.UUID, part); m_parts.Add(part.UUID, part);
@ -1074,6 +1160,7 @@ namespace OpenSim.Region.Framework.Scenes
if (part.LinkNum == 2 && RootPart != null) if (part.LinkNum == 2 && RootPart != null)
RootPart.LinkNum = 1; RootPart.LinkNum = 1;
} }
lockPartsForWrite(false);
} }
/// <summary> /// <summary>
@ -1081,28 +1168,33 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
private void UpdateParentIDs() private void UpdateParentIDs()
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part.UUID != m_rootPart.UUID) if (part.UUID != m_rootPart.UUID)
{ {
part.ParentID = m_rootPart.LocalId; part.ParentID = m_rootPart.LocalId;
} }
} }
} }
lockPartsForRead(false);
} }
public void RegenerateFullIDs() public void RegenerateFullIDs()
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.UUID = UUID.Random(); part.UUID = UUID.Random();
} }
} }
lockPartsForRead(false);
} }
// helper provided for parts. // helper provided for parts.
@ -1183,9 +1275,11 @@ namespace OpenSim.Region.Framework.Scenes
DetachFromBackup(); DetachFromBackup();
lock (m_parts) lockPartsForRead(true);
{ List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
foreach (SceneObjectPart part in m_parts.Values) lockPartsForRead(false);
foreach (SceneObjectPart part in values)
{ {
// part.Inventory.RemoveScriptInstances(); // part.Inventory.RemoveScriptInstances();
@ -1204,8 +1298,10 @@ namespace OpenSim.Region.Framework.Scenes
avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
} }
} }
} }
}
} }
public void AddScriptLPS(int count) public void AddScriptLPS(int count)
@ -1230,17 +1326,20 @@ namespace OpenSim.Region.Framework.Scenes
scriptEvents aggregateScriptEvents=0; scriptEvents aggregateScriptEvents=0;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part == null) if (part == null)
continue; continue;
if (part != RootPart) if (part != RootPart)
part.ObjectFlags = objectflagupdate; part.ObjectFlags = objectflagupdate;
aggregateScriptEvents |= part.AggregateScriptEvents; aggregateScriptEvents |= part.AggregateScriptEvents;
} }
} }
lockPartsForRead(false);
m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0); m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0); m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
@ -1273,42 +1372,52 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="m_physicalPrim"></param> /// <param name="m_physicalPrim"></param>
public void ApplyPhysics(bool m_physicalPrim) public void ApplyPhysics(bool m_physicalPrim)
{ {
lock (m_parts) lockPartsForRead(true);
{
if (m_parts.Count > 1) if (m_parts.Count > 1)
{ {
List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
lockPartsForRead(false);
m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in values)
{ {
if (part.LocalId != m_rootPart.LocalId) if (part.LocalId != m_rootPart.LocalId)
{ {
part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim); part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
} }
}
}
// Hack to get the physics scene geometries in the right spot // Hack to get the physics scene geometries in the right spot
ResetChildPrimPhysicsPositions(); ResetChildPrimPhysicsPositions();
} }
else else
{ {
lockPartsForRead(false);
m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim); m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
} }
} }
}
public void SetOwnerId(UUID userId) public void SetOwnerId(UUID userId)
{ {
ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); ForEachPart(delegate(SceneObjectPart part)
{
part.OwnerID = userId;
});
} }
public void ForEachPart(Action<SceneObjectPart> whatToDo) public void ForEachPart(Action<SceneObjectPart> whatToDo)
{ {
lock (m_parts) lockPartsForRead(true);
{ List<SceneObjectPart> values = new List<SceneObjectPart>(m_parts.Values);
foreach (SceneObjectPart part in m_parts.Values) lockPartsForRead(false);
foreach (SceneObjectPart part in values)
{ {
whatToDo(part); whatToDo(part);
}
} }
} }
@ -1407,14 +1516,17 @@ namespace OpenSim.Region.Framework.Scenes
{ {
SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID)); SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part != RootPart) if (part != RootPart)
SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID)); SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
} }
} }
lockPartsForRead(false);
} }
/// <summary> /// <summary>
@ -1509,10 +1621,11 @@ namespace OpenSim.Region.Framework.Scenes
List<SceneObjectPart> partList; List<SceneObjectPart> partList;
lock (m_parts) lockPartsForRead(true);
{
partList = new List<SceneObjectPart>(m_parts.Values); partList = new List<SceneObjectPart>(m_parts.Values);
}
lockPartsForRead(false);
partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
{ {
@ -1835,10 +1948,11 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
newPart.SetParent(this); newPart.SetParent(this);
lock (m_parts) lockPartsForWrite(true);
{ {
m_parts.Add(newPart.UUID, newPart); m_parts.Add(newPart.UUID, newPart);
} }
lockPartsForWrite(false);
SetPartAsNonRoot(newPart); SetPartAsNonRoot(newPart);
@ -1901,7 +2015,7 @@ namespace OpenSim.Region.Framework.Scenes
//if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
// return; // return;
lock (m_parts) lockPartsForRead(true);
{ {
bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
@ -1919,34 +2033,43 @@ namespace OpenSim.Region.Framework.Scenes
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.SendScheduledUpdates(); part.SendScheduledUpdates();
} }
} }
lockPartsForRead(false);
} }
public void ScheduleFullUpdateToAvatar(ScenePresence presence) public void ScheduleFullUpdateToAvatar(ScenePresence presence)
{ {
RootPart.AddFullUpdateToAvatar(presence); RootPart.AddFullUpdateToAvatar(presence);
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part != RootPart) if (part != RootPart)
part.AddFullUpdateToAvatar(presence); part.AddFullUpdateToAvatar(presence);
} }
} }
lockPartsForRead(false);
} }
public void ScheduleTerseUpdateToAvatar(ScenePresence presence) public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.AddTerseUpdateToAvatar(presence); part.AddTerseUpdateToAvatar(presence);
} }
} }
lockPartsForRead(false);
} }
/// <summary> /// <summary>
@ -1957,14 +2080,17 @@ namespace OpenSim.Region.Framework.Scenes
checkAtTargets(); checkAtTargets();
RootPart.ScheduleFullUpdate(); RootPart.ScheduleFullUpdate();
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part != RootPart) if (part != RootPart)
part.ScheduleFullUpdate(); part.ScheduleFullUpdate();
} }
} }
lockPartsForRead(false);
} }
/// <summary> /// <summary>
@ -1972,13 +2098,16 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public void ScheduleGroupForTerseUpdate() public void ScheduleGroupForTerseUpdate()
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.ScheduleTerseUpdate(); part.ScheduleTerseUpdate();
} }
} }
lockPartsForRead(false);
} }
/// <summary> /// <summary>
@ -1991,14 +2120,17 @@ namespace OpenSim.Region.Framework.Scenes
RootPart.SendFullUpdateToAllClients(); RootPart.SendFullUpdateToAllClients();
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part != RootPart) if (part != RootPart)
part.SendFullUpdateToAllClients(); part.SendFullUpdateToAllClients();
} }
} }
lockPartsForRead(false);
} }
/// <summary> /// <summary>
@ -2030,13 +2162,14 @@ namespace OpenSim.Region.Framework.Scenes
if (IsDeleted) if (IsDeleted)
return; return;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
part.SendTerseUpdateToAllClients(); part.SendTerseUpdateToAllClients();
} }
} }
lockPartsForRead(false);
} }
#endregion #endregion
@ -2050,16 +2183,18 @@ namespace OpenSim.Region.Framework.Scenes
/// <returns>null if no child part with that linknum or child part</returns> /// <returns>null if no child part with that linknum or child part</returns>
public SceneObjectPart GetLinkNumPart(int linknum) public SceneObjectPart GetLinkNumPart(int linknum)
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
if (part.LinkNum == linknum) if (part.LinkNum == linknum)
{ {
lockPartsForRead(false);
return part; return part;
} }
} }
} }
lockPartsForRead(false);
return null; return null;
} }
@ -2087,17 +2222,19 @@ namespace OpenSim.Region.Framework.Scenes
public SceneObjectPart GetChildPart(uint localID) public SceneObjectPart GetChildPart(uint localID)
{ {
//m_log.DebugFormat("Entered looking for {0}", localID); //m_log.DebugFormat("Entered looking for {0}", localID);
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
//m_log.DebugFormat("Found {0}", part.LocalId); //m_log.DebugFormat("Found {0}", part.LocalId);
if (part.LocalId == localID) if (part.LocalId == localID)
{ {
lockPartsForRead(false);
return part; return part;
} }
} }
} }
lockPartsForRead(false);
return null; return null;
} }
@ -2127,17 +2264,19 @@ namespace OpenSim.Region.Framework.Scenes
public bool HasChildPrim(uint localID) public bool HasChildPrim(uint localID)
{ {
//m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID); //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
//m_log.DebugFormat("Found {0}", part.LocalId); //m_log.DebugFormat("Found {0}", part.LocalId);
if (part.LocalId == localID) if (part.LocalId == localID)
{ {
lockPartsForRead(false);
return true; return true;
} }
} }
} }
lockPartsForRead(false);
return false; return false;
} }
@ -2187,13 +2326,16 @@ namespace OpenSim.Region.Framework.Scenes
if (m_rootPart.LinkNum == 0) if (m_rootPart.LinkNum == 0)
m_rootPart.LinkNum = 1; m_rootPart.LinkNum = 1;
lock (m_parts) lockPartsForWrite(true);
{
m_parts.Add(linkPart.UUID, linkPart); m_parts.Add(linkPart.UUID, linkPart);
lockPartsForWrite(false);
// Insert in terms of link numbers, the new links // Insert in terms of link numbers, the new links
// before the current ones (with the exception of // before the current ones (with the exception of
// the root prim. Shuffle the old ones up // the root prim. Shuffle the old ones up
lockPartsForRead(true);
foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts) foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
{ {
if (kvp.Value.LinkNum != 1) if (kvp.Value.LinkNum != 1)
@ -2202,6 +2344,7 @@ namespace OpenSim.Region.Framework.Scenes
kvp.Value.LinkNum += objectGroup.PrimCount; kvp.Value.LinkNum += objectGroup.PrimCount;
} }
} }
lockPartsForRead(false);
linkPart.LinkNum = 2; linkPart.LinkNum = 2;
@ -2225,15 +2368,15 @@ namespace OpenSim.Region.Framework.Scenes
} }
part.ClearUndoState(); part.ClearUndoState();
} }
}
m_scene.UnlinkSceneObject(objectGroup.UUID, true); m_scene.UnlinkSceneObject(objectGroup.UUID, true);
objectGroup.m_isDeleted = true; objectGroup.m_isDeleted = true;
lock (objectGroup.m_parts) objectGroup.lockPartsForWrite(true);
{
objectGroup.m_parts.Clear(); objectGroup.m_parts.Clear();
}
objectGroup.lockPartsForWrite(false);
// Can't do this yet since backup still makes use of the root part without any synchronization // Can't do this yet since backup still makes use of the root part without any synchronization
// objectGroup.m_rootPart = null; // objectGroup.m_rootPart = null;
@ -2292,11 +2435,12 @@ namespace OpenSim.Region.Framework.Scenes
Quaternion worldRot = linkPart.GetWorldRotation(); Quaternion worldRot = linkPart.GetWorldRotation();
// Remove the part from this object // Remove the part from this object
lock (m_parts) lockPartsForWrite(true);
{ {
m_parts.Remove(linkPart.UUID); m_parts.Remove(linkPart.UUID);
} }
lockPartsForWrite(false);
lockPartsForRead(true);
if (m_parts.Count == 1 && RootPart != null) //Single prim is left if (m_parts.Count == 1 && RootPart != null) //Single prim is left
RootPart.LinkNum = 0; RootPart.LinkNum = 0;
else else
@ -2307,6 +2451,7 @@ namespace OpenSim.Region.Framework.Scenes
p.LinkNum--; p.LinkNum--;
} }
} }
lockPartsForRead(false);
linkPart.ParentID = 0; linkPart.ParentID = 0;
linkPart.LinkNum = 0; linkPart.LinkNum = 0;
@ -2624,9 +2769,10 @@ namespace OpenSim.Region.Framework.Scenes
if (selectionPart != null) if (selectionPart != null)
{ {
lock (m_parts) lockPartsForRead(true);
{ List<SceneObjectPart> parts = new List<SceneObjectPart>(m_parts.Values);
foreach (SceneObjectPart part in m_parts.Values) lockPartsForRead(false);
foreach (SceneObjectPart part in parts)
{ {
if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0) if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
{ {
@ -2635,11 +2781,11 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in parts)
{ {
part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
} }
}
} }
} }
@ -2863,7 +3009,7 @@ namespace OpenSim.Region.Framework.Scenes
prevScale.Z *= z; prevScale.Z *= z;
part.Resize(prevScale); part.Resize(prevScale);
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart obPart in m_parts.Values) foreach (SceneObjectPart obPart in m_parts.Values)
{ {
@ -2882,6 +3028,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
lockPartsForRead(false);
if (part.PhysActor != null) if (part.PhysActor != null)
{ {
@ -2962,7 +3109,7 @@ namespace OpenSim.Region.Framework.Scenes
axDiff *= Quaternion.Inverse(partRotation); axDiff *= Quaternion.Inverse(partRotation);
diff = axDiff; diff = axDiff;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart obPart in m_parts.Values) foreach (SceneObjectPart obPart in m_parts.Values)
{ {
@ -2972,6 +3119,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
lockPartsForRead(false);
AbsolutePosition = newPos; AbsolutePosition = newPos;
@ -3089,7 +3237,7 @@ namespace OpenSim.Region.Framework.Scenes
m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
} }
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart prim in m_parts.Values) foreach (SceneObjectPart prim in m_parts.Values)
{ {
@ -3107,6 +3255,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
lockPartsForRead(false);
m_rootPart.ScheduleTerseUpdate(); m_rootPart.ScheduleTerseUpdate();
} }
@ -3205,7 +3354,7 @@ namespace OpenSim.Region.Framework.Scenes
if (atTargets.Count > 0) if (atTargets.Count > 0)
{ {
uint[] localids = new uint[0]; uint[] localids = new uint[0];
lock (m_parts) lockPartsForRead(true);
{ {
localids = new uint[m_parts.Count]; localids = new uint[m_parts.Count];
int cntr = 0; int cntr = 0;
@ -3215,6 +3364,7 @@ namespace OpenSim.Region.Framework.Scenes
cntr++; cntr++;
} }
} }
lockPartsForRead(false);
for (int ctr = 0; ctr < localids.Length; ctr++) for (int ctr = 0; ctr < localids.Length; ctr++)
{ {
@ -3233,7 +3383,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
//trigger not_at_target //trigger not_at_target
uint[] localids = new uint[0]; uint[] localids = new uint[0];
lock (m_parts) lockPartsForRead(true);
{ {
localids = new uint[m_parts.Count]; localids = new uint[m_parts.Count];
int cntr = 0; int cntr = 0;
@ -3243,6 +3393,7 @@ namespace OpenSim.Region.Framework.Scenes
cntr++; cntr++;
} }
} }
lockPartsForRead(false);
for (int ctr = 0; ctr < localids.Length; ctr++) for (int ctr = 0; ctr < localids.Length; ctr++)
{ {
@ -3256,19 +3407,20 @@ namespace OpenSim.Region.Framework.Scenes
public float GetMass() public float GetMass()
{ {
float retmass = 0f; float retmass = 0f;
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
retmass += part.GetMass(); retmass += part.GetMass();
} }
} }
lockPartsForRead(false);
return retmass; return retmass;
} }
public void CheckSculptAndLoad() public void CheckSculptAndLoad()
{ {
lock (m_parts) lockPartsForRead(true);
{ {
if (!IsDeleted) if (!IsDeleted)
{ {
@ -3293,6 +3445,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
lockPartsForRead(false);
} }
protected void AssetReceived(string id, Object sender, AssetBase asset) protected void AssetReceived(string id, Object sender, AssetBase asset)
@ -3313,7 +3466,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="client"></param> /// <param name="client"></param>
public void SetGroup(UUID GroupID, IClientAPI client) public void SetGroup(UUID GroupID, IClientAPI client)
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
{ {
@ -3323,7 +3476,7 @@ namespace OpenSim.Region.Framework.Scenes
HasGroupChanged = true; HasGroupChanged = true;
} }
lockPartsForRead(false);
ScheduleGroupForFullUpdate(); ScheduleGroupForFullUpdate();
} }
@ -3342,11 +3495,12 @@ namespace OpenSim.Region.Framework.Scenes
public void SetAttachmentPoint(byte point) public void SetAttachmentPoint(byte point)
{ {
lock (m_parts) lockPartsForRead(true);
{ {
foreach (SceneObjectPart part in m_parts.Values) foreach (SceneObjectPart part in m_parts.Values)
part.SetAttachmentPoint(point); part.SetAttachmentPoint(point);
} }
lockPartsForRead(false);
} }
#region ISceneObject #region ISceneObject

View File

@ -2950,8 +2950,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return m_host.OwnerID.ToString(); return m_host.OwnerID.ToString();
} }
[DebuggerNonUserCode]
public void llInstantMessage(string user, string message) public void llInstantMessage(string user, string message)
{ {
UUID result;
if (!UUID.TryParse(user, out result))
{
throw new Exception(String.Format("An invalid key of '{0} was passed to llInstantMessage", user));
return;
}
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
// We may be able to use ClientView.SendInstantMessage here, but we need a client instance. // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.

View File

@ -101,6 +101,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private Dictionary<UUID, IScriptInstance> m_Scripts = private Dictionary<UUID, IScriptInstance> m_Scripts =
new Dictionary<UUID, IScriptInstance>(); new Dictionary<UUID, IScriptInstance>();
private OpenMetaverse.ReaderWriterLockSlim m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
// Maps the asset ID to the assembly // Maps the asset ID to the assembly
private Dictionary<UUID, string> m_Assemblies = private Dictionary<UUID, string> m_Assemblies =
@ -122,6 +124,65 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue(); private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue();
IWorkItemResult m_CurrentCompile = null; IWorkItemResult m_CurrentCompile = null;
private void lockScriptsForRead(bool locked)
{
if (locked)
{
if (m_scriptsLock.RecursiveReadCount > 0)
{
m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
m_scriptsLock.ExitReadLock();
}
if (m_scriptsLock.RecursiveWriteCount > 0)
{
m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
m_scriptsLock.ExitWriteLock();
}
while (!m_scriptsLock.TryEnterReadLock(60000))
{
m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire READ lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
if (m_scriptsLock.IsWriteLockHeld)
{
m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
}
}
}
else
{
m_scriptsLock.ExitReadLock();
}
}
private void lockScriptsForWrite(bool locked)
{
if (locked)
{
if (m_scriptsLock.RecursiveReadCount > 0)
{
m_log.Error("[XEngine.m_Scripts] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue.");
m_scriptsLock.ExitReadLock();
}
if (m_scriptsLock.RecursiveWriteCount > 0)
{
m_log.Error("[XEngine.m_Scripts] Recursive write lock requested. This should not happen and means something needs to be fixed.");
m_scriptsLock.ExitWriteLock();
}
while (!m_scriptsLock.TryEnterWriteLock(60000))
{
m_log.Error("[XEngine.m_Scripts] Thread lock detected while trying to aquire WRITE lock of m_scripts in XEngine. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed.");
if (m_scriptsLock.IsWriteLockHeld)
{
m_scriptsLock = new OpenMetaverse.ReaderWriterLockSlim();
}
}
}
else
{
m_scriptsLock.ExitWriteLock();
}
}
public string ScriptEngineName public string ScriptEngineName
{ {
get { return "XEngine"; } get { return "XEngine"; }
@ -261,8 +322,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
{ {
lock (m_Scripts) lockScriptsForRead(true);
{
foreach (IScriptInstance instance in m_Scripts.Values) foreach (IScriptInstance instance in m_Scripts.Values)
{ {
// Force a final state save // Force a final state save
@ -293,11 +353,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
UnloadAppDomain(instance.AppDomain); UnloadAppDomain(instance.AppDomain);
} }
} }
lockScriptsForRead(false);
lockScriptsForWrite(true);
m_Scripts.Clear(); m_Scripts.Clear();
lockScriptsForWrite(false);
m_PrimObjects.Clear(); m_PrimObjects.Clear();
m_Assemblies.Clear(); m_Assemblies.Clear();
m_DomainScripts.Clear(); m_DomainScripts.Clear();
}
lock (m_ScriptEngines) lock (m_ScriptEngines)
{ {
m_ScriptEngines.Remove(this); m_ScriptEngines.Remove(this);
@ -356,22 +419,20 @@ namespace OpenSim.Region.ScriptEngine.XEngine
List<IScriptInstance> instances = new List<IScriptInstance>(); List<IScriptInstance> instances = new List<IScriptInstance>();
lock (m_Scripts) lockScriptsForRead(true);
{
foreach (IScriptInstance instance in m_Scripts.Values) foreach (IScriptInstance instance in m_Scripts.Values)
instances.Add(instance); instances.Add(instance);
} lockScriptsForRead(false);
foreach (IScriptInstance i in instances) foreach (IScriptInstance i in instances)
{ {
string assembly = String.Empty; string assembly = String.Empty;
lock (m_Scripts)
{
if (!m_Assemblies.ContainsKey(i.AssetID)) if (!m_Assemblies.ContainsKey(i.AssetID))
continue; continue;
assembly = m_Assemblies[i.AssetID]; assembly = m_Assemblies[i.AssetID];
}
i.SaveState(assembly); i.SaveState(assembly);
} }
@ -673,14 +734,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
return false; return false;
} }
lock (m_Scripts)
{
ScriptInstance instance = null; ScriptInstance instance = null;
// Create the object record // Create the object record
lockScriptsForRead(true);
if ((!m_Scripts.ContainsKey(itemID)) || if ((!m_Scripts.ContainsKey(itemID)) ||
(m_Scripts[itemID].AssetID != assetID)) (m_Scripts[itemID].AssetID != assetID))
{ {
lockScriptsForRead(false);
UUID appDomain = assetID; UUID appDomain = assetID;
if (part.ParentGroup.IsAttachment) if (part.ParentGroup.IsAttachment)
@ -753,10 +816,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
instance.AppDomain = appDomain; instance.AppDomain = appDomain;
instance.LineMap = linemap; instance.LineMap = linemap;
lockScriptsForWrite(true);
m_Scripts[itemID] = instance; m_Scripts[itemID] = instance;
lockScriptsForWrite(false);
}
else
{
lockScriptsForRead(false);
} }
lock (m_PrimObjects) lock (m_PrimObjects)
{ {
if (!m_PrimObjects.ContainsKey(localID)) if (!m_PrimObjects.ContainsKey(localID))
@ -777,21 +844,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (instance!=null) if (instance!=null)
instance.Init(); instance.Init();
}
return true; return true;
} }
public void OnRemoveScript(uint localID, UUID itemID) public void OnRemoveScript(uint localID, UUID itemID)
{ {
lock (m_Scripts) lockScriptsForRead(true);
{
// Do we even have it? // Do we even have it?
if (!m_Scripts.ContainsKey(itemID)) if (!m_Scripts.ContainsKey(itemID))
{
lockScriptsForRead(false);
return; return;
}
IScriptInstance instance=m_Scripts[itemID]; IScriptInstance instance=m_Scripts[itemID];
lockScriptsForRead(false);
lockScriptsForWrite(true);
m_Scripts.Remove(itemID); m_Scripts.Remove(itemID);
lockScriptsForWrite(false);
instance.ClearQueue(); instance.ClearQueue();
instance.Stop(0); instance.Stop(0);
@ -838,7 +910,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
handlerObjectRemoved(part.UUID); handlerObjectRemoved(part.UUID);
CleanAssemblies(); CleanAssemblies();
}
ScriptRemoved handlerScriptRemoved = OnScriptRemoved; ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
if (handlerScriptRemoved != null) if (handlerScriptRemoved != null)
@ -1091,12 +1163,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private IScriptInstance GetInstance(UUID itemID) private IScriptInstance GetInstance(UUID itemID)
{ {
IScriptInstance instance; IScriptInstance instance;
lock (m_Scripts) lockScriptsForRead(true);
{
if (!m_Scripts.ContainsKey(itemID)) if (!m_Scripts.ContainsKey(itemID))
{
lockScriptsForRead(false);
return null; return null;
instance = m_Scripts[itemID];
} }
instance = m_Scripts[itemID];
lockScriptsForRead(false);
return instance; return instance;
} }
@ -1200,11 +1274,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
{ {
List<IScriptInstance> instances = new List<IScriptInstance>(); List<IScriptInstance> instances = new List<IScriptInstance>();
lock (m_Scripts) lockScriptsForRead(true);
{
foreach (IScriptInstance instance in m_Scripts.Values) foreach (IScriptInstance instance in m_Scripts.Values)
instances.Add(instance); instances.Add(instance);
} lockScriptsForRead(false);
foreach (IScriptInstance i in instances) foreach (IScriptInstance i in instances)
{ {