From d49cd9fc77405183abf8d8b9d4690b14fa82ab58 Mon Sep 17 00:00:00 2001 From: Kei Kamikawa Date: Sun, 3 Nov 2024 14:35:59 +0900 Subject: [PATCH] added attachmentWasDisconnectedWithError delegate in internal only --- virtualization_11.h | 22 +++++++- virtualization_11.m | 127 +++++++++++++++++++++++++++++++++++++++--- virtualization_view.m | 2 +- 3 files changed, 141 insertions(+), 10 deletions(-) diff --git a/virtualization_11.h b/virtualization_11.h index 95f2f532..6c748225 100644 --- a/virtualization_11.h +++ b/virtualization_11.h @@ -8,6 +8,7 @@ #import "virtualization_helper.h" #import +#import /* exported from cgo */ void connectionHandler(void *connection, void *err, uintptr_t cgoHandle); @@ -18,6 +19,18 @@ bool shouldAcceptNewConnectionHandler(uintptr_t cgoHandle, void *connection, voi - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; @end +@interface VZVirtualMachineDelegateWrapper : NSObject +@property (nonatomic, strong, readonly) NSHashTable> *delegates; + +- (instancetype)init; +- (void)addDelegate:(id)delegate; +- (void)guestDidStopVirtualMachine:(VZVirtualMachine *)virtualMachine; +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine didStopWithError:(NSError *)error; +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine + networkDevice:(VZNetworkDevice *)networkDevice + attachmentWasDisconnectedWithError:(NSError *)error API_AVAILABLE(macos(12.0)); +@end + @interface ObservableVZVirtualMachine : VZVirtualMachine - (instancetype)initWithConfiguration:(VZVirtualMachineConfiguration *)configuration queue:(dispatch_queue_t)queue @@ -25,6 +38,13 @@ bool shouldAcceptNewConnectionHandler(uintptr_t cgoHandle, void *connection, voi - (void)dealloc; @end +@interface VZVirtualMachineNetworkDeviceErrorHandler : NSObject +- (instancetype)initWithHandle:(uintptr_t)cgoHandle; +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine + networkDevice:(VZNetworkDevice *)networkDevice + attachmentWasDisconnectedWithError:(NSError *)error API_AVAILABLE(macos(12.0)); +@end + /* VZVirtioSocketListener */ @interface VZVirtioSocketListenerDelegateImpl : NSObject - (instancetype)initWithHandle:(uintptr_t)cgoHandle; @@ -88,7 +108,7 @@ void VZVirtioSocketDevice_removeSocketListenerForPort(void *socketDevice, void * void VZVirtioSocketDevice_connectToPort(void *socketDevice, void *vmQueue, uint32_t port, uintptr_t cgoHandle); /* VirtualMachine */ -void *newVZVirtualMachineWithDispatchQueue(void *config, void *queue, uintptr_t cgoHandle); +void *newVZVirtualMachineWithDispatchQueue(void *config, void *queue, uintptr_t statusUpdateCgoHandle); bool requestStopVirtualMachine(void *machine, void *queue, void **error); void startWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle); void pauseWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle); diff --git a/virtualization_11.m b/virtualization_11.m index d2d898fd..68c42b08 100644 --- a/virtualization_11.m +++ b/virtualization_11.m @@ -17,26 +17,133 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N } @end +@implementation VZVirtualMachineDelegateWrapper +- (instancetype)init +{ + self = [super init]; + if (self) { + _delegates = [NSHashTable weakObjectsHashTable]; + } + return self; +} + +- (void)addDelegate:(id)delegate +{ + [self.delegates addObject:delegate]; +} + +- (void)guestDidStopVirtualMachine:(VZVirtualMachine *)virtualMachine +{ + for (id delegate in self.delegates) { + if ([delegate respondsToSelector:@selector(guestDidStopVirtualMachine:)]) { + [delegate guestDidStopVirtualMachine:virtualMachine]; + } + } +} + +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine didStopWithError:(NSError *)error +{ + for (id delegate in self.delegates) { + if ([delegate respondsToSelector:@selector(virtualMachine:didStopWithError:)]) { + [delegate virtualMachine:virtualMachine didStopWithError:error]; + } + } +} + +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine networkDevice:(VZNetworkDevice *)networkDevice + attachmentWasDisconnectedWithError:(NSError *)error +{ + for (id delegate in self.delegates) { + if ([delegate respondsToSelector:@selector(virtualMachine:networkDevice:attachmentWasDisconnectedWithError:)]) { + [delegate virtualMachine:virtualMachine networkDevice:networkDevice attachmentWasDisconnectedWithError:error]; + } + } +} +@end + +@implementation VZVirtualMachineNetworkDeviceErrorHandler { + uintptr_t _cgoHandle; +} + +// TODO(codehex): Support the conditions under which the attachmentWasDisconnectedWithError method +// is executed as soon as they are known. +- (instancetype)initWithHandle:(uintptr_t)cgoHandle +{ + self = [super init]; + if (self) { + _cgoHandle = cgoHandle; + } + return self; +} + +- (void)virtualMachine:(VZVirtualMachine *)virtualMachine + networkDevice:(VZNetworkDevice *)networkDevice + attachmentWasDisconnectedWithError:(NSError *)error +{ + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + NSString *processName = [processInfo processName]; + NSString *osVersion = [processInfo operatingSystemVersionString]; + struct utsname systemInfo; + uname(&systemInfo); + NSString *architecture = [NSString stringWithCString:systemInfo.machine + encoding:NSUTF8StringEncoding]; + + NSLog( + @"If you see this message, please report the information about the OS (including the version) that you are running on the VM, " + @"along with the information displayed below, to https://github.com/Code-Hex/vz/issues.\n" + @"Process Information:\n" + @" Name: %@\n" + @" macOS: %@, %@\n" + @" networkDevice: %@\n" + @" networkDevice attachment: %@\n", + @" attachmentWasDisconnectedWithError: %@", + processName, + osVersion, + architecture, + networkDevice, + networkDevice.attachment, + error); +} +@end + @implementation ObservableVZVirtualMachine { Observer *_observer; + VZVirtualMachineDelegateWrapper *_delegateWrapper; }; - (instancetype)initWithConfiguration:(VZVirtualMachineConfiguration *)configuration queue:(dispatch_queue_t)queue statusUpdateHandle:(uintptr_t)statusUpdateHandle { self = [super initWithConfiguration:configuration queue:queue]; - _observer = [[Observer alloc] init]; - [self addObserver:_observer - forKeyPath:@"state" - options:NSKeyValueObservingOptionNew - context:(void *)statusUpdateHandle]; + if (self) { + _observer = [[Observer alloc] init]; + [self addObserver:_observer + forKeyPath:@"state" + options:NSKeyValueObservingOptionNew + context:(void *)statusUpdateHandle]; + _delegateWrapper = [[VZVirtualMachineDelegateWrapper alloc] init]; + [super setDelegate:_delegateWrapper]; + } return self; } +- (void)setDelegate:(id)delegate +{ + if (delegate != _delegateWrapper) { + [_delegateWrapper addDelegate:delegate]; + } +} + +- (id)delegate +{ + return _delegateWrapper; +} + - (void)dealloc { [self removeObserver:_observer forKeyPath:@"state"]; [_observer release]; + [_delegateWrapper release]; [super dealloc]; } @end @@ -48,7 +155,9 @@ @implementation VZVirtioSocketListenerDelegateImpl { - (instancetype)initWithHandle:(uintptr_t)cgoHandle { self = [super init]; - _cgoHandle = cgoHandle; + if (self) { + _cgoHandle = cgoHandle; + } return self; } @@ -731,13 +840,15 @@ VZVirtioSocketConnectionFlat convertVZVirtioSocketConnection2Flat(void *connecti Every operation on the virtual machine must be done on that queue. The callbacks and delegate methods are invoked on that queue. If the queue is not serial, the behavior is undefined. */ -void *newVZVirtualMachineWithDispatchQueue(void *config, void *queue, uintptr_t cgoHandle) +void *newVZVirtualMachineWithDispatchQueue(void *config, void *queue, uintptr_t statusUpdateCgoHandle) { if (@available(macOS 11, *)) { ObservableVZVirtualMachine *vm = [[ObservableVZVirtualMachine alloc] initWithConfiguration:(VZVirtualMachineConfiguration *)config queue:(dispatch_queue_t)queue - statusUpdateHandle:cgoHandle]; + statusUpdateHandle:statusUpdateCgoHandle]; + VZVirtualMachineNetworkDeviceErrorHandler *delegate = [[[VZVirtualMachineNetworkDeviceErrorHandler alloc] init] autorelease]; + [vm setDelegate:delegate]; return vm; } diff --git a/virtualization_view.m b/virtualization_view.m index 7ff298b2..9fbf6d18 100644 --- a/virtualization_view.m +++ b/virtualization_view.m @@ -178,7 +178,7 @@ - (instancetype)initWithVirtualMachine:(VZVirtualMachine *)virtualMachine { self = [super init]; _virtualMachine = virtualMachine; - _virtualMachine.delegate = self; + [_virtualMachine setDelegate:self]; // Setup virtual machine view configs VZVirtualMachineView *view = [[[VZVirtualMachineView alloc] init] autorelease];