From d1147136946daf14724183b3191119be44ff8b16 Mon Sep 17 00:00:00 2001 From: CasperW Date: Tue, 24 Nov 2009 18:02:12 +0100 Subject: Drop all locking of part.TaskInventory in favour of a ReaderWriterLockSlim lock handler. This gives us: - Faster prim inventory actions. Multiple threads can read at once. - Fixes the known prim inventory thread locks - In the event of a thread lock occurring, it will usually self heal after sixty seconds with an error message in the console --- OpenSim/Framework/TaskInventoryDictionary.cs | 111 +++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/TaskInventoryDictionary.cs') diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs index 25ae6b0..efe5f0c 100644 --- a/OpenSim/Framework/TaskInventoryDictionary.cs +++ b/OpenSim/Framework/TaskInventoryDictionary.cs @@ -27,9 +27,12 @@ using System; using System.Collections.Generic; +using System.Threading; +using System.Reflection; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; +using log4net; using OpenMetaverse; namespace OpenSim.Framework @@ -45,6 +48,105 @@ namespace OpenSim.Framework // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static XmlSerializer tiiSerializer = new XmlSerializer(typeof (TaskInventoryItem)); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Thread LockedByThread; + /// + /// An advanced lock for inventory data + /// + private System.Threading.ReaderWriterLockSlim m_itemLock = new System.Threading.ReaderWriterLockSlim(); + + /// + /// Are we readlocked by the calling thread? + /// + public bool IsReadLockedByMe() + { + if (m_itemLock.RecursiveReadCount > 0) + { + return true; + } + else + { + return false; + } + } + + /// + /// Lock our inventory list for reading (many can read, one can write) + /// + public void LockItemsForRead(bool locked) + { + if (locked) + { + if (m_itemLock.IsWriteLockHeld && LockedByThread != null) + { + if (!LockedByThread.IsAlive) + { + //Locked by dead thread, reset. + m_itemLock = new System.Threading.ReaderWriterLockSlim(); + } + } + + if (m_itemLock.RecursiveReadCount > 0) + { + m_log.Error("[TaskInventoryDictionary] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); + m_itemLock.ExitReadLock(); + } + if (m_itemLock.RecursiveWriteCount > 0) + { + m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed."); + m_itemLock.ExitWriteLock(); + } + + while (!m_itemLock.TryEnterReadLock(60000)) + { + m_log.Error("Thread lock detected while trying to aquire READ lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); + if (m_itemLock.IsWriteLockHeld) + { + m_itemLock = new System.Threading.ReaderWriterLockSlim(); + } + } + } + else + { + m_itemLock.ExitReadLock(); + } + } + + /// + /// Lock our inventory list for writing (many can read, one can write) + /// + public void LockItemsForWrite(bool locked) + { + if (locked) + { + //Enter a write lock, wait indefinately for one to open. + if (m_itemLock.RecursiveReadCount > 0) + { + m_log.Error("[TaskInventoryDictionary] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); + m_itemLock.ExitReadLock(); + } + if (m_itemLock.RecursiveWriteCount > 0) + { + m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed."); + m_itemLock.ExitWriteLock(); + } + while (!m_itemLock.TryEnterWriteLock(60000)) + { + m_log.Error("Thread lock detected while trying to aquire WRITE lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); + if (m_itemLock.IsWriteLockHeld) + { + m_itemLock = new System.Threading.ReaderWriterLockSlim(); + } + } + + LockedByThread = Thread.CurrentThread; + } + else + { + m_itemLock.ExitWriteLock(); + } + } #region ICloneable Members @@ -52,13 +154,12 @@ namespace OpenSim.Framework { TaskInventoryDictionary clone = new TaskInventoryDictionary(); - lock (this) + m_itemLock.EnterReadLock(); + foreach (UUID uuid in Keys) { - foreach (UUID uuid in Keys) - { - clone.Add(uuid, (TaskInventoryItem) this[uuid].Clone()); - } + clone.Add(uuid, (TaskInventoryItem) this[uuid].Clone()); } + m_itemLock.ExitReadLock(); return clone; } -- cgit v1.1