mirror of https://github.com/cirruslabs/tart.git
Report errors thrown inside tart run's fire-and-forget tasks
We were discarding any error thrown inside these unstructured tasks, which silently hid failures to run the control socket or to start and stop the VM, and which the compiler now warns about. Wrap them in an ErrorReportingTask, which spawns the task and reports any thrown error to stderr, rather than repeating a do/catch at every call site. An unstructured task spawned from a synchronous context (a signal handler or SwiftUI action) has no parent to propagate the error to, so reporting it is the best we can do.
This commit is contained in:
parent
1f556051b0
commit
43ebbc31df
|
|
@ -514,7 +514,7 @@ struct Run: AsyncParsableCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(macOS 14, *) {
|
if #available(macOS 14, *) {
|
||||||
Task {
|
ErrorReportingTask("Failed to run control socket") {
|
||||||
try await ControlSocket(vmDir.controlSocketURL).run()
|
try await ControlSocket(vmDir.controlSocketURL).run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -586,7 +586,7 @@ struct Run: AsyncParsableCommand {
|
||||||
signal(SIGUSR2, SIG_IGN)
|
signal(SIGUSR2, SIG_IGN)
|
||||||
let sigusr2Src = DispatchSource.makeSignalSource(signal: SIGUSR2)
|
let sigusr2Src = DispatchSource.makeSignalSource(signal: SIGUSR2)
|
||||||
sigusr2Src.setEventHandler {
|
sigusr2Src.setEventHandler {
|
||||||
Task {
|
ErrorReportingTask("Failed to request guest OS to stop") {
|
||||||
print("Requesting guest OS to stop...")
|
print("Requesting guest OS to stop...")
|
||||||
try vm!.virtualMachine.requestStop()
|
try vm!.virtualMachine.requestStop()
|
||||||
}
|
}
|
||||||
|
|
@ -798,13 +798,13 @@ struct MainApp: App {
|
||||||
CommandGroup(replacing: .appInfo) { AboutTart(config: vm!.config) }
|
CommandGroup(replacing: .appInfo) { AboutTart(config: vm!.config) }
|
||||||
CommandMenu("Control") {
|
CommandMenu("Control") {
|
||||||
Button("Start") {
|
Button("Start") {
|
||||||
Task { try await vm!.virtualMachine.start() }
|
ErrorReportingTask("Failed to start VM") { try await vm!.virtualMachine.start() }
|
||||||
}
|
}
|
||||||
Button("Stop") {
|
Button("Stop") {
|
||||||
Task { try await vm!.virtualMachine.stop() }
|
ErrorReportingTask("Failed to stop VM") { try await vm!.virtualMachine.stop() }
|
||||||
}
|
}
|
||||||
Button("Request Stop") {
|
Button("Request Stop") {
|
||||||
Task { try vm!.virtualMachine.requestStop() }
|
ErrorReportingTask("Failed to request VM stop") { try vm!.virtualMachine.requestStop() }
|
||||||
}
|
}
|
||||||
if #available(macOS 14, *) {
|
if #available(macOS 14, *) {
|
||||||
if (MainApp.suspendable) {
|
if (MainApp.suspendable) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,23 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
// A fire-and-forget task that reports any thrown error to stderr. An unstructured
|
||||||
|
// Task spawned from a synchronous context (a signal handler, a SwiftUI action) has
|
||||||
|
// no parent to propagate its error to, so we report it here instead of dropping it.
|
||||||
|
struct ErrorReportingTask {
|
||||||
|
let task: Task<Void, Never>
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
init(_ context: String, operation: @escaping @Sendable () async throws -> Void) {
|
||||||
|
task = Task {
|
||||||
|
do {
|
||||||
|
try await operation()
|
||||||
|
} catch {
|
||||||
|
fputs("\(context): \(error)\n", stderr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension Collection {
|
extension Collection {
|
||||||
subscript (safe index: Index) -> Element? {
|
subscript (safe index: Index) -> Element? {
|
||||||
indices.contains(index) ? self[index] : nil
|
indices.contains(index) ? self[index] : nil
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue