fix: on some machines, deadlocks happened at launch
This commit is contained in:
1 parent
126eca5c35
commit
e2181c8756
2 files changed
+11
-9
No files matched your search
@@ -10,8 +10,6 @@ class BackgroundWork {
|
|||||||
|
|
||||||
// we cap concurrent tasks to .processorCount to avoid thread explosion on the .global queue
|
// we cap concurrent tasks to .processorCount to avoid thread explosion on the .global queue
|
||||||
static let globalSemaphore = DispatchSemaphore(value: ProcessInfo.processInfo.processorCount)
|
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
|
// swift static variables are lazy; we artificially force the threads to init
|
||||||
static func start() {
|
static func start() {
|
||||||
@@ -25,12 +23,12 @@ extension DispatchQueue {
|
|||||||
return DispatchQueue(label: label, target: .global(qos: qos.qosClass))
|
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 = {
|
let block = {
|
||||||
fn()
|
fn()
|
||||||
semaphore.signal()
|
BackgroundWork.globalSemaphore.signal()
|
||||||
}
|
}
|
||||||
semaphore.wait()
|
BackgroundWork.globalSemaphore.wait()
|
||||||
if let deadline = deadline {
|
if let deadline = deadline {
|
||||||
asyncAfter(deadline: deadline, execute: block)
|
asyncAfter(deadline: deadline, execute: block)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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
|
// 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()) {
|
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 {
|
do {
|
||||||
try fn()
|
try fn()
|
||||||
} catch {
|
} catch {
|
||||||
let timePassedInSeconds = Double(DispatchTime.now().uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000
|
let timePassedInSeconds = Double(DispatchTime.now().uptimeNanoseconds - startTime.uptimeNanoseconds) / 1_000_000_000
|
||||||
if timePassedInSeconds < Double(AXUIElement.globalTimeoutInSeconds) {
|
if timePassedInSeconds < Double(AXUIElement.globalTimeoutInSeconds) {
|
||||||
BackgroundWork.axCallsQueue.asyncWithCap(.now() + .milliseconds(10), semaphore: BackgroundWork.axCallsGlobalSemaphore) {
|
BackgroundWork.axCallsQueue.asyncAfter(deadline: .now() + .milliseconds(10)) {
|
||||||
retryAxCallUntilTimeout(fn, startTime)
|
retryAxCallUntilTimeout_(fn, startTime)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user