From 4f6c59781b88d8581545377fc5be1a309f857035 Mon Sep 17 00:00:00 2001 From: sbohlen Date: Fri, 27 Aug 2010 20:48:56 +0000 Subject: [PATCH] SPRNET-1330 -introduce singleton-specific lock object registration to prevent against deadlocks when any one singleton create/destroy op calls arbitrarily long user-supplied methods that may or may not block --- .../Factory/Support/AbstractObjectFactory.cs | 105 +++++++++++++----- 1 file changed, 77 insertions(+), 28 deletions(-) diff --git a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs index 6888486a..4190ed0c 100644 --- a/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs +++ b/src/Spring/Spring.Core/Objects/Factory/Support/AbstractObjectFactory.cs @@ -142,6 +142,12 @@ namespace Spring.Objects.Factory.Support /// private readonly Hashtable factoryObjectProductCache = new Hashtable(); + + /// + /// Collection of singleton-specific locks to support locking singleton-specific critical sections + /// + private IDictionary singletonLocks = new Hashtable(); + #region Constructor (s) / Destructor /// @@ -1438,16 +1444,28 @@ namespace Spring.Objects.Factory.Support /// protected virtual void DestroySingleton(string name) { + object tempObject; + lock (singletonCache) { - object tempObject = singletonCache[name]; - singletonCache.Remove(name); - registeredSingletons.Remove(name); - - object singletonInstance = tempObject; - if (singletonInstance != null) + tempObject = singletonCache[name]; + + if (tempObject!=null) { - DestroyObject(name, singletonInstance); + singletonCache.Remove(name); + registeredSingletons.Remove(name); + } + + if (tempObject!=null) + { + lock(GetSingletonLockFor(name)) + { + object singletonInstance = tempObject; + if (singletonInstance != null) + { + DestroyObject(name, singletonInstance); + } + } } } } @@ -2122,35 +2140,48 @@ namespace Spring.Objects.Factory.Support RootObjectDefinition objectDefinition, object[] arguments) { + object sharedInstance; + lock (singletonCache) { - object sharedInstance = singletonCache[objectName]; + sharedInstance = singletonCache[objectName]; + if (sharedInstance == null) { - #region Instrumentation - if (log.IsDebugEnabled) + lock (GetSingletonLockFor(objectName)) { - log.Debug(string.Format("Creating shared instance of singleton object '{0}'", objectName)); - } - #endregion + lock (singletonCache) + { + if (singletonCache.Contains(objectName)) + { + return singletonCache[objectName]; + } + } + #region Instrumentation + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Creating shared instance of singleton object '{0}'", objectName)); + } + #endregion - BeforeSingletonCreation(objectName); - try - { - sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false); - } - finally - { - AfterSingletonCreation(objectName); - } - AddSingleton(objectName, sharedInstance); + BeforeSingletonCreation(objectName); + try + { + sharedInstance = InstantiateObject(objectName, objectDefinition, arguments, true, false); + } + finally + { + AfterSingletonCreation(objectName); + } + AddSingleton(objectName, sharedInstance); - #region Instrumentation - if (log.IsDebugEnabled) - { - log.Debug(string.Format("Cached shared instance of singleton object '{0}'", objectName)); + #region Instrumentation + if (log.IsDebugEnabled) + { + log.Debug(string.Format("Cached shared instance of singleton object '{0}'", objectName)); + } + #endregion } - #endregion } return sharedInstance; } @@ -2485,5 +2516,23 @@ namespace Spring.Objects.Factory.Support { return IsAlias(objectName) || ContainsLocalObject(objectName); } + + + /// + /// Gets the singleton lock for a given object name. + /// + /// Name of the object. + /// lock object + private object GetSingletonLockFor(string objectName) + { + lock (singletonCache) + { + if (!singletonLocks.Contains(objectName)) + { + singletonLocks.Add(objectName, new object()); + } + return singletonLocks[objectName]; + } + } } } \ No newline at end of file