mirror of
https://github.com/cirruslabs/tart.git
synced 2026-09-29 18:51:19 +02:00
Run ErrorReportingTask operations on the caller's actor (#1324)
VZVirtualMachine asserts that it is used on the queue it was created with, which for tart is the main queue. Since #1262 replaced the unstructured Task in "tart run"'s SIGUSR2 handler with ErrorReportingTask, that assertion fails: Task.init carries @_inheritActorContext, but ErrorReportingTask.init did not, so an operation written inside MainActor-isolated Run.runOnMainThread() is formed in a nonisolated init and runs on the cooperative pool, not the main queue. The result is that asking a VM to stop gracefully kills it instead. Sending SIGUSR2, which #842 hooked to requestStop() for exactly this purpose, crashes the process: Thread 1 queue: com.apple.root.default-qos.cooperative _dispatch_assert_queue_fail dispatch_assert_queue -[VZVirtualMachine requestStopWithError:] closure in Run.runOnMainThread() closure in ErrorReportingTask.init(_:operation:) The guest then loses power without a chance to flush, and on a Linux guest with ext4's default delayed allocation that discards whatever had not been written back yet. The same applies to the requestStop() in applicationShouldTerminate(), i.e. closing the window of a VM run with a GUI. Give the operation the same @_inheritActorContext that Task.init has, so that wrapping a call in ErrorReportingTask no longer changes where it runs. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
cdb3579c79
commit
9bb2af2434
@@ -6,8 +6,11 @@ import Foundation
|
||||
struct ErrorReportingTask {
|
||||
let task: Task<Void, Never>
|
||||
|
||||
// Inherit the caller's actor context, exactly as Task.init does. Without this, an
|
||||
// operation written inside a @MainActor function runs on the cooperative pool
|
||||
// rather than the main queue, trapping in callees that assert their queue.
|
||||
@discardableResult
|
||||
init(_ context: String, operation: @escaping @Sendable () async throws -> Void) {
|
||||
init(_ context: String, @_inheritActorContext operation: @escaping @Sendable () async throws -> Void) {
|
||||
task = Task {
|
||||
do {
|
||||
try await operation()
|
||||
|
||||
Reference in New Issue
Block a user