Răsfoiți Sursa

managers: avoid priority inversions

1. Stop using the default background queue because it is designed for actual
   background tasks.
2. Create named queues when applicable. This helps debugging.
3. VM operations, JSON parsing, and QMP handling are all the same priority
   now and therefore avoids priority inversion.

Fixes #4352
osy 2 ani în urmă
părinte
comite
7073f0317a

+ 1 - 1
Managers/UTMJSONStream.m

@@ -145,7 +145,7 @@ enum ParserState {
     }
     }
     NSAssert([json isKindOfClass:[NSDictionary class]], @"JSON data not dictionary");
     NSAssert([json isKindOfClass:[NSDictionary class]], @"JSON data not dictionary");
     UTMLog(@"Debug JSON recieved <- %@", json);
     UTMLog(@"Debug JSON recieved <- %@", json);
-    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
         [self.delegate jsonStream:self receivedDictionary:(NSDictionary *)json];
         [self.delegate jsonStream:self receivedDictionary:(NSDictionary *)json];
     });
     });
 }
 }

+ 9 - 1
Managers/UTMQemu.m

@@ -20,6 +20,12 @@
 #import <pthread.h>
 #import <pthread.h>
 #import <TargetConditionals.h>
 #import <TargetConditionals.h>
 
 
+@interface UTMQemu ()
+
+@property (nonatomic) dispatch_queue_t completionQueue;
+
+@end
+
 @implementation UTMQemu {
 @implementation UTMQemu {
     NSMutableArray<NSString *> *_argv;
     NSMutableArray<NSString *> *_argv;
     NSMutableArray<NSURL *> *_urls;
     NSMutableArray<NSURL *> *_urls;
@@ -54,6 +60,8 @@
         if (![self setupXpc]) {
         if (![self setupXpc]) {
             return nil;
             return nil;
         }
         }
+        dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, QOS_MIN_RELATIVE_PRIORITY);
+        self.completionQueue = dispatch_queue_create("QEMU Completion Queue", attr);
     }
     }
     return self;
     return self;
 }
 }
@@ -144,7 +152,7 @@
     pthread_attr_init(&qosAttribute);
     pthread_attr_init(&qosAttribute);
     pthread_attr_set_qos_class_np(&qosAttribute, QOS_CLASS_USER_INTERACTIVE, 0);
     pthread_attr_set_qos_class_np(&qosAttribute, QOS_CLASS_USER_INTERACTIVE, 0);
     pthread_create(&qemu_thread, &qosAttribute, self.entry, (__bridge_retained void *)self);
     pthread_create(&qemu_thread, &qosAttribute, self.entry, (__bridge_retained void *)self);
-    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+    dispatch_async(self.completionQueue, ^{
         if (dispatch_semaphore_wait(self.done, DISPATCH_TIME_FOREVER)) {
         if (dispatch_semaphore_wait(self.done, DISPATCH_TIME_FOREVER)) {
             dlclose(dlctx);
             dlclose(dlctx);
             completion(NO, NSLocalizedString(@"Internal error has occurred.", @"UTMQemu"));
             completion(NO, NSLocalizedString(@"Internal error has occurred.", @"UTMQemu"));

+ 3 - 3
Managers/UTMQemuManager.m

@@ -254,7 +254,7 @@ void qmp_rpc_call(CFDictionaryRef args, CFDictionaryRef *ret, Error **err, void
 }
 }
 
 
 - (void)qmpPowerCommand:(NSString *)command completion:(void (^ _Nullable)(NSError * _Nullable))completion {
 - (void)qmpPowerCommand:(NSString *)command completion:(void (^ _Nullable)(NSError * _Nullable))completion {
-    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
         Error *qerr = NULL;
         Error *qerr = NULL;
         NSError *err;
         NSError *err;
         NSDictionary *cmd = @{
         NSDictionary *cmd = @{
@@ -272,7 +272,7 @@ void qmp_rpc_call(CFDictionaryRef args, CFDictionaryRef *ret, Error **err, void
 }
 }
 
 
 - (void)qmpHmpCommand:(NSString *)cmd completion:(void (^)(NSString * _Nullable, NSError * _Nullable))completion {
 - (void)qmpHmpCommand:(NSString *)cmd completion:(void (^)(NSString * _Nullable, NSError * _Nullable))completion {
-    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
         Error *qerr = NULL;
         Error *qerr = NULL;
         NSError *err;
         NSError *err;
         NSString *result;
         NSString *result;
@@ -323,7 +323,7 @@ void qmp_rpc_call(CFDictionaryRef args, CFDictionaryRef *ret, Error **err, void
 }
 }
 
 
 - (void)mouseIndexForAbsolute:(BOOL)absolute withCompletion:(void (^)(int64_t, NSError * _Nullable))completion {
 - (void)mouseIndexForAbsolute:(BOOL)absolute withCompletion:(void (^)(int64_t, NSError * _Nullable))completion {
-    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
         MouseInfoList *info = NULL;
         MouseInfoList *info = NULL;
         Error *qerr = NULL;
         Error *qerr = NULL;
         int64_t index = -1;
         int64_t index = -1;

+ 2 - 1
Managers/UTMQemuVirtualMachine.m

@@ -74,7 +74,8 @@ NSString *const kSuspendSnapshotName = @"suspend";
         self.qemuWillQuitEvent = dispatch_semaphore_create(0);
         self.qemuWillQuitEvent = dispatch_semaphore_create(0);
         self.qemuDidExitEvent = dispatch_semaphore_create(0);
         self.qemuDidExitEvent = dispatch_semaphore_create(0);
         self.qemuDidConnectEvent = dispatch_semaphore_create(0);
         self.qemuDidConnectEvent = dispatch_semaphore_create(0);
-        self.vmOperations = dispatch_queue_create("com.utmapp.UTM.VMOperations", DISPATCH_QUEUE_SERIAL);
+        dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
+        self.vmOperations = dispatch_queue_create("com.utmapp.UTM.VMOperations", attr);
     }
     }
     return self;
     return self;
 }
 }

+ 1 - 1
Platform/iOS/VMSessionState.swift

@@ -39,7 +39,7 @@ import SwiftUI
     #if !WITH_QEMU_TCI
     #if !WITH_QEMU_TCI
     private var primaryUsbManager: CSUSBManager?
     private var primaryUsbManager: CSUSBManager?
     
     
-    private var usbManagerQueue = DispatchQueue(label: "USB Manager Queue", qos: .background)
+    private var usbManagerQueue = DispatchQueue(label: "USB Manager Queue", qos: .utility)
     
     
     @Published var mostRecentConnectedDevice: CSUSBDevice?
     @Published var mostRecentConnectedDevice: CSUSBDevice?
     
     

+ 3 - 3
Platform/macOS/Display/VMDisplayQemuDisplayController.swift

@@ -363,7 +363,7 @@ extension VMDisplayQemuWindowController: CSUSBManagerDelegate {
             guard response == .alertFirstButtonReturn else {
             guard response == .alertFirstButtonReturn else {
                 return
                 return
             }
             }
-            DispatchQueue.global(qos: .background).async {
+            DispatchQueue.global(qos: .utility).async {
                 usbManager.connectUsbDevice(usbDevice) { (result, message) in
                 usbManager.connectUsbDevice(usbDevice) { (result, message) in
                     DispatchQueue.main.async {
                     DispatchQueue.main.async {
                         if let msg = message {
                         if let msg = message {
@@ -445,7 +445,7 @@ extension VMDisplayQemuWindowController {
             return
             return
         }
         }
         let device = allUsbDevices[menu.tag]
         let device = allUsbDevices[menu.tag]
-        DispatchQueue.global(qos: .background).async {
+        DispatchQueue.global(qos: .utility).async {
             usbManager.connectUsbDevice(device) { (result, message) in
             usbManager.connectUsbDevice(device) { (result, message) in
                 DispatchQueue.main.async {
                 DispatchQueue.main.async {
                     if let msg = message {
                     if let msg = message {
@@ -469,7 +469,7 @@ extension VMDisplayQemuWindowController {
             return
             return
         }
         }
         let device = allUsbDevices[menu.tag]
         let device = allUsbDevices[menu.tag]
-        DispatchQueue.global(qos: .background).async {
+        DispatchQueue.global(qos: .utility).async {
             usbManager.disconnectUsbDevice(device) { (result, message) in
             usbManager.disconnectUsbDevice(device) { (result, message) in
                 DispatchQueue.main.async {
                 DispatchQueue.main.async {
                     if let msg = message {
                     if let msg = message {

+ 2 - 6
Platform/macOS/Display/VMDisplayWindowController.swift

@@ -82,9 +82,7 @@ class VMDisplayWindowController: NSWindowController {
     
     
     @IBAction func restartButtonPressed(_ sender: Any) {
     @IBAction func restartButtonPressed(_ sender: Any) {
         showConfirmAlert(NSLocalizedString("This will reset the VM and any unsaved state will be lost.", comment: "VMDisplayWindowController")) {
         showConfirmAlert(NSLocalizedString("This will reset the VM and any unsaved state will be lost.", comment: "VMDisplayWindowController")) {
-            DispatchQueue.global(qos: .background).async {
-                self.vm.requestVmReset()
-            }
+            self.vm.requestVmReset()
         }
         }
     }
     }
     
     
@@ -245,9 +243,7 @@ extension VMDisplayWindowController: NSWindowDelegate {
     
     
     func windowWillClose(_ notification: Notification) {
     func windowWillClose(_ notification: Notification) {
         if !isSecondary {
         if !isSecondary {
-            DispatchQueue.global(qos: .background).async {
-                self.vm.requestVmStop(force: true)
-            }
+            self.vm.requestVmStop(force: true)
         }
         }
         secondaryWindows.forEach { secondaryWindow in
         secondaryWindows.forEach { secondaryWindow in
             secondaryWindow.close()
             secondaryWindow.close()