queueHandler: use SimpleQueue rather than Queue#11373
Conversation
…Queue is much more light-wait and reduces the chance of deadlocks.
…aracter notifications rather than using queueEvent as queueEvent may cause a deadlock with the app who sent the typed character notification if Python's garbage collector runs and releases a COM object from that process during queueEvent's lock.
| focus=api.getFocusObject() | ||
| if focus.windowClassName!="ConsoleWindowClass": | ||
| eventHandler.queueEvent("typedCharacter",focus,ch=ch) | ||
| # Manually queue a call to executeEvent rather than using queueEvent, |
There was a problem hiding this comment.
Have you considered either one of the following:
- Adding an additional kwarg to eventHandler.queueEvent that allows bypassing the pending events system. If that kwarg is semi private (e.g. by prefixing it with an underscore), it won't hurt anyone and it simplifies the API.
- Tune the behavior of the garbage collector, i.e. by disabling the automatic collection and running the garbage collector manually at certain intervals, within the core pump, etc. Alternatively, we could temporarily disable collection in situations that could cause deadlocks.
There was a problem hiding this comment.
|
@michaelDCurran First of all, glad to see something is done about this long standing issue. From the description I gather this must be a hell to debug/pinpoint the core issue. Definitely out of scope for this PR, but I guess Python's garbage collector and COM can cause way more hard to catch issues. Ever considered moving COM-interaction out of the Python code base and into a low-level language like C/C++? |
|
More information about the introduction of |
| # As Currently queueEvent uses a lock and there is a small chance it could deadlock | ||
| # If garbage collection within the lock | ||
| # caused a COM object from the same thread as the typed character to be released. | ||
| queueHandler.queueFunction( |
There was a problem hiding this comment.
This bypasses the pendingEvents mechanism. Perhaps it is worth investigating disabling the garbage collection?
|
I think it is better to explicitly avoid queueEvent here, rather than changing queueEvent's functionality (even if based on a private argument) to bypass the pending events mechanism. Otherwise, queueEvent's functionality becomes harder to understand and predict. |
|
So this means that specifically for typed character events, the pending events mechanism isn't going to be used anymore? Why not do the same of all types of events? |
|
Pending events is used for Focus, Caret, ValueChange and TextChange, I believe. Especially caret handling will probably break in a major way if we'd remove that mechanism. |
|
Prior to this PR it was also used for typed character events. I'd like to know why is this mechanism important for the events you listed, but not so for the typed character event. This now means that |
|
I'm not too sure what more I can say other than that we have no code in
NVDA that relies on asking if there are pending typed character events.
Yet there is a great deal of code that relies on asking if there are
pending gainFocus, caret and valueChange events.
This change really is to avoid a very nasty freeze. I think that
dropping the idea of tracking typedCharacter events while they are
pending is worth it.
If we can completely avoid the possibility of running garbage collection
within the queueEvent lock in future, then I'm happy to re-instate this
code.
|
|
I have reverted the typedCharacterNotify change in pr #11416, but kept the change from Queue to SimpleQueue. We can try and address the possible freeze in queueEvent when in typedCharacterNotify either with better garbage collection management, avoiding doing in-process typed character processing at all in Windows 10, or by somehow making the in-process part of typedCharacterNotify non-blocking. |
This might be worth considering (we already do this for terminals). Can you think of any drawbacks? |
|
We may be able to avoid in-process typedCharacter support entirely for
newer versions of Windows 10, but previous to that we must still do
in-process. However, we can change the in-process code to not block when
doing this. I'm working on a pr for non-blocking in-process
typedCharacter support currently.
|
|
|
Correct. But not Windows 7, which we still have a lot of users for.
|
Yes, but are users of an end of life OS going to update their screen reader? Do you have stats on this? (I imagine probably hard to get them as due to security issues lots of Win7 machines are run exclusively offline) |
|
Hi, surprisingly, yes, as evidenced by people using 2016 and 2017 releases of NVDA on older operating systems. I guess it won’t be until next year or 2022 when we need to think about Windows 7 support, but that won’t happen until a change in NVDA that will necessitate dropping support for anything under Windows 8.1. Thanks.
From: Bill Dengler <notifications@github.com>
Sent: Sunday, July 26, 2020 3:50 PM
To: nvaccess/nvda <nvda@noreply.github.com>
Cc: Subscribed <subscribed@noreply.github.com>
Subject: Re: [nvaccess/nvda] queueHandler: use SimpleQueue rather than Queue (#11373)
Correct. But not Windows 7, which we still have a lot of users for.
Yes, but are users of an end of life OS <https://www.microsoft.com/en-us/microsoft-365/windows/end-of-windows-7-support> going to update their screen reader?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub <#11373 (comment)> , or unsubscribe <https://github.com/notifications/unsubscribe-auth/AB4AXEFI3WSBPSJERVNH4ETR5SXKPANCNFSM4OZEGFAA> .
|
Link to issue number:
Closes #11369
Summary of the issue:
It is possible for both NVDA and an app (such as Microsoft Word) to both deadlock when typing characters.
The process is as follows:
4.1. Python's garbage collector runs and or Python deletes objects that are no longer in scope.
4.2. One or more of these objects are comtypes COM objects marshalled from the app's main thread that sent the typed character notification.
4.3. Python calls Release on one of these COM objects which waits upon the app's main thread to release the object. Deadlock.
Even if this were addressed, a second deadlock is possible:
4.1. During the lock, Python's garbage collector runs and or Python deletes objects that are no longer in scope.
4.2. One or more of these objects are comtypes COM objects marshalled from the app's main thread that sent the typed character notification.
4.3. Python calls Release on one of these COM objects which waits upon the app's main thread to release the object. Deadlock.
Description of changes
Both of these changes ensure that no locks are entered during that particular incoming RPC call.
Testing performed
Tried to make MS Word / NVDA freeze by typing very fast into a document for at least 30 seconds. No freeze was experienced.
Known Issues
I don't believe there any drawbacks to these changes, though they may not address the issue as specifically as they could. The root of the problem still remains that
Changelog
Bug fixes: