In SceneViewer, introduce an IsEnabled flag and perform Close() under an m_pendingObjects lock in order to avoid the race condition seen by danbanner in http://opensimulator.org/mantis/view.php?id=5669

remove-scene-viewer
Justin Clark-Casey (justincc) 2011-09-06 22:26:28 +01:00
parent 1a8f5b97b9
commit 4bf3adffb8
2 changed files with 51 additions and 19 deletions

View File

@ -30,12 +30,21 @@ using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
{ {
/// <summary>
/// Sends scheduled updates to it's associated ScenePresence.
/// </summary>
public interface ISceneViewer public interface ISceneViewer
{ {
void Reset(); void Reset();
void Close(); void Close();
/// <summary>
/// Add the part to the queue of parts for which we need to send an update to the client
/// </summary>
/// <param name="part"></param>
void QueuePartForUpdate(SceneObjectPart part); void QueuePartForUpdate(SceneObjectPart part);
void SendPrimUpdates(); void SendPrimUpdates();
int GetPendingObjectsCount(); int GetPendingObjectsCount();
} }
} }

View File

@ -38,27 +38,42 @@ namespace OpenSim.Region.Framework.Scenes
{ {
public class SceneViewer : ISceneViewer public class SceneViewer : ISceneViewer
{ {
/// <summary>
/// Is this scene viewer enabled?
/// </summary>
private bool IsEnabled { get; set; }
/// <summary>
/// The scene presence serviced by this viewer.
/// </summary>
protected ScenePresence m_presence; protected ScenePresence m_presence;
/// <summary>
/// The queue of parts for which we need to send out updates.
/// </summary>
protected UpdateQueue m_partsUpdateQueue = new UpdateQueue(); protected UpdateQueue m_partsUpdateQueue = new UpdateQueue();
/// <summary>
/// The queue of objects for which we need to send out updates.
/// </summary>
protected Queue<SceneObjectGroup> m_pendingObjects; protected Queue<SceneObjectGroup> m_pendingObjects;
/// <summary>
/// The last update assocated with a given part update.
/// </summary>
protected Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>(); protected Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>();
public SceneViewer()
{
}
public SceneViewer(ScenePresence presence) public SceneViewer(ScenePresence presence)
{ {
m_presence = presence; m_presence = presence;
IsEnabled = true;
} }
/// <summary>
/// Add the part to the queue of parts for which we need to send an update to the client
/// </summary>
/// <param name="part"></param>
public void QueuePartForUpdate(SceneObjectPart part) public void QueuePartForUpdate(SceneObjectPart part)
{ {
if (!IsEnabled)
return;
lock (m_partsUpdateQueue) lock (m_partsUpdateQueue)
{ {
m_partsUpdateQueue.Enqueue(part); m_partsUpdateQueue.Enqueue(part);
@ -87,6 +102,11 @@ namespace OpenSim.Region.Framework.Scenes
lock (m_pendingObjects) lock (m_pendingObjects)
{ {
// We must do this under lock so that we don't suffer a race condition if another thread closes the
// viewer
if (!IsEnabled)
return;
while (m_pendingObjects != null && m_pendingObjects.Count > 0) while (m_pendingObjects != null && m_pendingObjects.Count > 0)
{ {
SceneObjectGroup g = m_pendingObjects.Dequeue(); SceneObjectGroup g = m_pendingObjects.Dequeue();
@ -119,7 +139,6 @@ namespace OpenSim.Region.Framework.Scenes
// We deal with the possibility that two updates occur at // We deal with the possibility that two updates occur at
// the same unix time at the update point itself. // the same unix time at the update point itself.
if ((update.LastFullUpdateTime < part.TimeStampFull) || part.ParentGroup.IsAttachment) if ((update.LastFullUpdateTime < part.TimeStampFull) || part.ParentGroup.IsAttachment)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
@ -135,9 +154,7 @@ namespace OpenSim.Region.Framework.Scenes
// this update. If this happened, then subsequent // this update. If this happened, then subsequent
// updates which occurred on the same tick or the // updates which occurred on the same tick or the
// next tick of the last update would be ignored. // next tick of the last update would be ignored.
update.LastFullUpdateTime = part.TimeStampFull; update.LastFullUpdateTime = part.TimeStampFull;
} }
else if (update.LastTerseUpdateTime <= part.TimeStampTerse) else if (update.LastTerseUpdateTime <= part.TimeStampTerse)
{ {
@ -193,15 +210,21 @@ namespace OpenSim.Region.Framework.Scenes
public void Close() public void Close()
{ {
lock (m_updateTimes) lock (m_pendingObjects)
{ {
m_updateTimes.Clear(); IsEnabled = false;
lock (m_updateTimes)
{
m_updateTimes.Clear();
}
lock (m_partsUpdateQueue)
{
m_partsUpdateQueue.Clear();
}
Reset();
} }
lock (m_partsUpdateQueue)
{
m_partsUpdateQueue.Clear();
}
Reset();
} }
public int GetPendingObjectsCount() public int GetPendingObjectsCount()