fix: on some machines, deadlocks happened at launch

This commit is contained in:
Louis Pontoise authored and lwouis committed 2020-07-11 03:31:50 +09:00
1 parent 126eca5c35
commit e2181c8756
2 files changed
+11 -9

No files matched your search

+3 -5
View File
@@ -10,8 +10,6 @@ class BackgroundWork {
// we cap concurrent tasks to .processorCount to avoid thread explosion on the .global queue
static let globalSemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.processorCount)
// AX calls may block for a long time. We use a big semaphore to avoid blocking the main thread in case the window server is busy
static let axCallsGlobalSemaphore = DispatchSemaphore(value: 100)
// swift static variables are lazy; we artificially force the threads to init
static func start() {
@@ -25,12 +23,12 @@ extension DispatchQueue {
return DispatchQueue(label: label, target: .global(qos: qos.qosClass))
}
func asyncWithCap(_ deadline: DispatchTime? = nil, semaphore: DispatchSemaphore = BackgroundWork.globalSemaphore, _ fn: @escaping () -> Void) {
func asyncWithCap(_ deadline: DispatchTime? = nil, _ fn: @escaping () -> Void) {
let block = {
fn()
semaphore.signal()
BackgroundWork.globalSemaphore.signal()
}
semaphore.wait()
BackgroundWork.globalSemaphore.wait()
if let deadline = deadline {
asyncAfter(deadline: deadline, execute: block)
} else {
+8 -4
View File
@@ -7,15 +7,19 @@ func axObserverCallback(observer: AXObserver, element: AXUIElement, notification
// if the window server is busy, it may not reply to AX calls. We retry right before the call times-out and returns a bogus value
func retryAxCallUntilTimeout(_ fn: @escaping () throws -> Void, _ startTime: DispatchTime = DispatchTime.now()) {
BackgroundWork.axCallsQueue.asyncWithCap(semaphore: BackgroundWork.axCallsGlobalSemaphore) {
BackgroundWork.axCallsQueue.async {
retryAxCallUntilTimeout_(fn, startTime)
}
}
func retryAxCallUntilTimeout_(_ fn: @escaping () throws -> Void, _ startTime: DispatchTime = DispatchTime.now()) {
do {
try fn()
} catch {
let timePassedInSeconds = Double(DispatchTime.now().uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000
if timePassedInSeconds < Double(AXUIElement.globalTimeoutInSeconds) {
BackgroundWork.axCallsQueue.asyncWithCap(.now() + .milliseconds(10), semaphore: BackgroundWork.axCallsGlobalSemaphore) {
retryAxCallUntilTimeout(fn, startTime)
}
BackgroundWork.axCallsQueue.asyncAfter(deadline: .now() + .milliseconds(10)) {
retryAxCallUntilTimeout_(fn, startTime)
}
}
}