-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deadlock at ExecuteSubmission vs LoggingService #6717
Deadlock at ExecuteSubmission vs LoggingService #6717
Conversation
…LoggingService" This reverts commit d761551.
Can you please post sample callstacks where this happens? Which |
In related issue #6712 there is screen shot of parallel stack view, which defines those conflicting callstacks. I will copy/paste bellow with detailed explanation: |
I tried splitting the lock in ExecuteSubmission in the past but ended up reverting it because I just couldn't reason about all the interleaving states :) The deadlock is happening because two threads want to achieve the same high level action at the same time: complete the logging for a given submission. So instead of dividing the locks, a less intrusive change would be to detect when two threads want to complete the same submission and have one of them back off. In this case, OnProjectFinished should back off if it sees that someone else (ExecuteSubmission) is completing the submission. |
In this particular deadlock instance the submission 'A' trying to be completed by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like a low-risk change but the deadlock has to be fixed. Let's give it a try 👍
// This method may be called in the shutdown submission callback, this callback may be called after the logging service has | ||
// shutdown and nulled out the events we were going to wait on. | ||
if (_logMode == LoggerMode.Asynchronous && _loggingQueue != null) | ||
lock (_lockObject) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change related to the fix or does it address another issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is another bug. TerminateLoggingEventQueue()
put LoggingService into state which will either silently reject events coming into its queue while it is waiting for all existing events to be handled.
Also CreateLoggingEventQueue()
modifies _loggingQueue
which shall be protected for concurrent access.
However, I will have to modify it, because the way I have fixed it, it could cause different deadlock, when any registered logger callback into LoggingService for example with intent to log something. That seems to me as quite possible.
I'll modify it and let you know.
Is it simply to ensure that when a build ends, nothing of the log is lost? It would be a surprise if eg., the build copied a file, but it didn't appear in the log as around the same time the build was canceled . |
- remaing local variable
Fixes #6823 Context There is possible deadlock in BuildManager vs LoggingService when: verbosity=diagnostic or higher or /bl LoggingService works in LoggerMode.Synchronous Changes Made LoggingService callbacks (OnProjectStarted, OnProjectFinished and OnThreadException) has been modified into async by leveraging existing workQueue. Testing Compiled Orchardcore in CLI and VS2022. Notes If these changes are considered safe, we can optionally revert PR #6717
Fixes #6712
Context
During blocking execution of
LoggingService.WaitForThreadToProcessEvents
fromBuildManager
, event processing can invoke callback into the sameBuildManager
instance and cause deadlock.Changes Made
Blocking execution of
LoggingService.WaitForThreadToProcessEvents
is now not called from inside of lock so thread handling event processing callback can than acquireBuildManager._syncLock
without deadlock.Core was reviewed considering possible state mutation during critical sections splitting =>
lock{}; other-thread-mutation; lock{}
and considered safe.Testing
Manual testing by throwing exception during code pause.
Notes
I was trying my best, but still, this code requires careful review!