question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

LockRecursionException thrown from various locations

See original GitHub issue

Description

We’ve just had a report from an Evoq customer who have a busy site and observe intermittent downtime caused by “thread-safe” code. Quick google finds a whole lot of similar reports dating back to 2011. Let’s put this one to bed once and for all.

https://www.dnnsharp.com/helpcenter/url-adapter/recursive-read-lock-acquisitions-not-allowed-in-this-mode http://www.dnnsoftware.com/forums/forumid/108/threadid/412632/scope/posts http://www.dnnsoftware.com/answers/help-with-error-recursive-read-lock-acquisitions-not-allowed-in-this-mode https://dnntracker.atlassian.net/browse/DNN-24111

Looking at the most recent report we received, out of 57k exceptions logged (40 per minute!) there are two prime sources which fail to acquire a lock:

InvokeContainerEvents

The exception is logged in various places in the UI lifecycle. For example

DotNetNuke.Services.Exceptions.Exceptions - System.Threading.LockRecursionException: Recursive read lock acquisitions not allowed in this mode.
   at System.Threading.ReaderWriterLockSlim.TryEnterReadLockCore(TimeoutTracker timeout)
   at System.Threading.ReaderWriterLockSlim.TryEnterReadLock(TimeoutTracker timeout)
   at DotNetNuke.Collections.Internal.ReaderWriterLockStrategy.GetReadLock(TimeSpan timeout)
   at DotNetNuke.UI.Containers.Container.InvokeContainerEvents(ContainerEventType containerEventType)
   at System.Web.UI.Control.InitRecursive(Control namingContainer)
   at System.Web.UI.Control.AddedControl(Control control, Int32 index)
   at DotNetNuke.UI.Skins.Pane.InjectModule(ModuleInfo module)

@mean2me and I tried to look for more usages of the ContainerEventListener and I could not find any. This extension point used is apparently not used at all by Platform itself or Evoq.

What I find weird is that this code actually acquires a lock. To only iterate over the listeners it should perfectly fine to simply get hold of the underlying SharedList#BackingList to get a non-thread safe collection instead.

SimpleContainer

Often when trying to access an element from the container the lock cannot be acquired. Here’s an example

DotNetNuke.Web.Common.Internal.DotNetNukeHttpApplication - System.Threading.LockRecursionException: Recursive read lock acquisitions not allowed in this mode.
   at System.Threading.ReaderWriterLockSlim.TryEnterReadLockCore(TimeoutTracker timeout)
   at System.Threading.ReaderWriterLockSlim.TryEnterReadLock(TimeoutTracker timeout)
   at DotNetNuke.Collections.Internal.ReaderWriterLockStrategy.GetReadLock(TimeSpan timeout)
   at DotNetNuke.ComponentModel.SimpleContainer.GetComponentType(Type contractType)
   at DotNetNuke.ComponentModel.SimpleContainer.GetComponent(Type contractType)
   at DotNetNuke.ComponentModel.AbstractContainer.GetComponent[TContract]()
   at DotNetNuke.ComponentModel.ComponentBase`2.get_Instance()
   at DotNetNuke.Entities.Urls.RewriterUtils.OmitFromRewriteProcessing(String localPath)
   at DotNetNuke.Common.Initialize.ProcessHttpModule(HttpRequest request, Boolean allowUnknownExtensions, Boolean checkOmitFromRewriteProcessing)
   at DotNetNuke.HttpModules.RequestFilter.RequestFilterModule.FilterRequest(Object sender, EventArgs e)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Discussion

Seems like the underlying problem for both problems is the SharedList. One possibility is that locks are not properly released and then the application fails to acquire a new one. Unfortunately it’s very hard to verify if that is true. While it will be impractical to replace or rewrite that class we could safely reduce the locks where they are not strictly necessary.

In the case of InvokeContainerEvents I think that there is no risk in skipping lock altogether. The consequence would be a possibility that certain executions do not get the latest state of the list in question. And so what? This code in Container.cs does not modify the collection at all and is executed at every request. The latter should also mean the removing the lock should improve performance.


As for the SimpleContainer I think the fix should be more decisive. It’s a mystery to me why this service locator pattern and homegrown “dependency injection container”. Maybe it is high time to replace with a well-established alternative? Some full-featured options offering good performance are DryIoC, LightInject or even Autofac.

Affected version

Probably all the way back to DNN 5. Maybe even before that but we don’t have the evidence.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
bdukescommented, Jul 27, 2018

I’d vote for Autofac to replace SimpleContainer

0reactions
mikebiguncommented, Oct 22, 2018

@daguiler, done.

Read more comments on GitHub >

github_iconTop Results From Across the Web

LockRecursionException Class (System.Threading)
The exception that is thrown when recursive entry into a lock is not compatible with the recursion policy for the lock.
Read more >
C# - Why I get LockRecursionException when using ...
This ensures that if an exception is thrown when writing a log message, the lock is always released: public static string Error(string log) ......
Read more >
DataCacheNode.NotifyDirtyTables throws System. ...
LockRecursionException occurred HResult=-2146233088. Message=Recursive write lock acquisitions not allowed in this mode. Source=System.Core
Read more >
Recursive read lock acquisitions not allowed in this mode
LockRecursionException Message: Recursive read lock acquisitions not allowed in this mode. Source: System.Core at System.Threading.
Read more >
- A read lock may not be acquired with the write lock held in ...
I am experiencing error on 'Factory.Reset()' threw an exception of type 'System.Threading.LockRecursionException' void {System.Threading.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found