Decouple BgThread from braille module#14312
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Co-authored-by: Sean Budd <seanbudd123@gmail.com>
This comment was marked as outdated.
This comment was marked as outdated.
Co-authored-by: Sean Budd <seanbudd123@gmail.com>
…, the display might send an ack after closing the handle, resulting in an error
|
Converting to draft due to merge conflicts. |
|
Solved merge conflicts and confirmed that stuff still works as expected. |
feerrenrut
left a comment
There was a problem hiding this comment.
I'm going to need to go over this again. But there are a few things I picked up this time.
|
|
||
|
|
||
| def _crashNVDA(): | ||
| def _crashNVDA(param: int = 0): |
There was a problem hiding this comment.
Can you add a docstring for this param? Or perhaps use a lambda or wrap the call to this to adapt it to the queueAsApc requirements.
| if self.thread: | ||
| return |
There was a problem hiding this comment.
It might be clearer if this class inherited from threading.Thread and the lifecycle of IoThread was managed by some owner.
There was a problem hiding this comment.
Thanks, good idea. I applied that suggestion.
| _BgThread.ackTimerHandle, | ||
| int(handler.display.timeout*2000), | ||
| self.ackTimerHandle, | ||
| int(self.display.timeout * 2000), |
There was a problem hiding this comment.
Do you know about this value? Why is it multiplied by 2000?
There was a problem hiding this comment.
It is converted to milli seconds and then multiplied by two. I added a descriptive comment.
There was a problem hiding this comment.
This would be clearer if the two intentions were separated (IE, twice time out, convert to MS). Using named constants is a step better than a comment because the name is more likely to be updated to stay correct than a nearby comment.
SECOND_TO_MS = 1000
winKernel.setWaitableTimer(
self.ackTimerHandle,
# Wait twice the display driver timeout for acknowledgement packets
# Note: timeout is in seconds whereas setWaitableTimer expects milliseconds
int(self.display.timeout * 2 * SECOND_TO_MS ),
See test results for failed build of commit 2fefdf0582 |
| _BgThread.ackTimerHandle, | ||
| int(handler.display.timeout*2000), | ||
| self.ackTimerHandle, | ||
| int(self.display.timeout * 2000), |
There was a problem hiding this comment.
This would be clearer if the two intentions were separated (IE, twice time out, convert to MS). Using named constants is a step better than a comment because the name is more likely to be updated to stay correct than a nearby comment.
SECOND_TO_MS = 1000
winKernel.setWaitableTimer(
self.ackTimerHandle,
# Wait twice the display driver timeout for acknowledgement packets
# Note: timeout is in seconds whereas setWaitableTimer expects milliseconds
int(self.display.timeout * 2 * SECOND_TO_MS ),
This comment was marked as outdated.
This comment was marked as outdated.
|
@LeonarddeR I've re-worded the developer change log entry, could you confirm the following is accurate: |
|
Yes, this is fine!
|
…s are safe (#14627) Follow up of #14312 Summary of the issue: In #14312, we decoupled the background I/O thread from the braille module. However, the thread was still bound to IoBase in it's _initialRead method unless you'd override it. While I hoped the changes in #14312 would decrease crashing of braille, this was indeed the cause. However, crashes are still occurring here and there. I'm pretty sure I know the cause lies in the IO done completion routines that are still executed on the IO thread without ensuring that the instances of the routines still exist. I've seen this causing several access violation errors. Furthermore, #14312 saved bound methods in a dictionary on the iOThread. While this shouldn't be a big problem, this could cause potential issues with garbage collection (i.e. instances being kept alife forever because the APC of an instance was never called and it would be stuck in the cached apc dictionary). Description of user facing changes Hopefully, more stability. Description of development approach Added the ioThread as a constructor method to IoBase and derivatives as an optional argument. If not provided (default), the default IoThread is used. It will be added as a weak reference on the IoBase instance. Thereby it is no longer necessary to subclass IoBase or a derivative to override _initialRead to use another thread. Added IoThread.setWaitableTimer and IoThread.getCompletionRoutine, also ensuring that the function pointers are available when the background thread tries to call them. The function wrapper keeps a weak reference to the method it wraps. Thereby it ensures that a method of a died instance is no longer executed. IoThread.queueAsApc still stores a strong reference to the wrapped method on its APC, to keep backwards compatibility. This will be changed to weak references starting in NVDA 2024.1. API deprecation logic is in place. Removed the pre_IoThreadStop extension point. It was added in 2023.1 but never implemented and announced, so I think it is safe to do so.
Related to #14899, #14312, #14627 Fixes #14895 Summary of the issue: Despite several attempts to fix this, NVDA's IoThread can crash without a clear cause. Description of user facing changes Less crashes, most likely, as tests indicate that this is the case. Description of development approach As proposed by @jcsteh , rather than creating a new function pointer for every APC or completion routine call, use a single internal APC and completion routine and use an internal cache to store the python functions, not the actual APC functions.
Link to issue number:
Closes #14130
Slightly related to #14147
Summary of the issue:
In #14130, I raised the concern that the background thread for i/o is too tightly coupled too the braille module. This required the hwIo module to queue an APC to the braille background thread.
Description of user facing changes
None, apart from more safety checks that might impose stability improvements.
Description of development approach
_initialReadmethod that initiates reading on the background thread. This method can be overridden on subclasses to outsource the reading to another thread.Point 1 and 3 above together solve my concerns as noted in #14130
Testing strategy:
We need to thoroughly test braille display i/o for these changes.
I ran the pr build for several days without noticeable impact, in fact I was under the impression that braille initialization time decreased slightly with this approach.
Known issues with pull request:
Change log entries:
For Developers
Code Review Checklist: