1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
// This file is a part of Julia. License is MIT: https://julialang.org/license
#import "ExecSandbox.h"
@class JuliaTask;
@interface ExecSandbox () {
NSMutableArray<JuliaTask *> *_Nonnull _tasks;
}
- (void)taskTerminated:(JuliaTask *_Nonnull)jt;
@end
@interface JuliaTask : NSObject <TaskProtocol> {
ExecSandbox *__weak _delegate;
dispatch_block_t _Nullable _onCleanup;
NSTask *_Nonnull _task;
}
@end
@implementation JuliaTask
- (instancetype)initWithTask:(NSTask *_Nonnull)task
delegate:(ExecSandbox *)d
cleanup:(dispatch_block_t)onCleanup {
self = [super init];
if (self == nil) {
return nil;
}
_delegate = d;
_onCleanup = onCleanup;
_task = task;
return self;
}
- (void)launch:(void (^_Nullable)(int status))onTermination {
dispatch_block_t onCleanup = _onCleanup;
JuliaTask __weak *weakSelf = self;
_task.terminationHandler = ^(NSTask *_Nonnull t) {
if (onTermination != nil) {
onTermination(t.terminationStatus);
}
if (onCleanup != nil) {
onCleanup();
}
JuliaTask *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf->_delegate taskTerminated:strongSelf];
}
};
@try {
[_task launch];
} @catch (NSException *exception) {
NSLog(@"NSTask launch exception: %@", exception);
}
}
- (void)terminate {
@try {
[_task terminate];
} @catch (NSException *exception) {
NSLog(@"NSTask terminate exception: %@", exception);
}
}
@end
@implementation ExecSandbox
- (instancetype)init {
self = [super init];
if (self == nil) {
return nil;
}
_tasks = [[NSMutableArray alloc] init];
return self;
}
- (void)eval:(NSString *)p
withJulia:(NSData *)executableBookmark
arguments:(NSArray<NSString *> *)baseArgs
task:(void (^)(id<TaskProtocol> task, NSFileHandle *stdIn,
NSFileHandle *stdOut, NSFileHandle *stdErr))reply {
NSURL *executableURL =
[NSURL URLByResolvingBookmarkData:executableBookmark
options:NSURLBookmarkResolutionWithoutUI
relativeToURL:nil
bookmarkDataIsStale:nil
error:nil];
if (executableURL == nil) {
reply(nil, nil, nil, nil);
return;
}
for (NSString *arg in baseArgs) {
if ([arg isEqual:@"--"]) {
reply(nil, nil, nil, nil);
return;
}
}
NSURL *temporaryDirectoryURL = [NSURL fileURLWithPath:NSTemporaryDirectory()
isDirectory:YES];
NSString *temporaryFilename =
[[NSProcessInfo processInfo] globallyUniqueString];
NSURL *temporaryFileURL =
[temporaryDirectoryURL URLByAppendingPathComponent:temporaryFilename
isDirectory:NO];
[[p dataUsingEncoding:NSUTF8StringEncoding] writeToURL:temporaryFileURL
atomically:NO];
NSMutableArray<NSString *> *args = [[NSMutableArray alloc] init];
[args addObjectsFromArray:baseArgs];
[args addObjectsFromArray:@[ @"--", temporaryFileURL.path ]];
NSPipe *stdIn = [NSPipe pipe], *stdOut = [NSPipe pipe],
*stdErr = [NSPipe pipe];
NSTask *t = [[NSTask alloc] init];
if (@available(macOS 10.13, *)) {
t.executableURL = executableURL;
} else {
t.launchPath = executableURL.path;
}
t.arguments = args;
t.standardInput = stdIn;
t.standardOutput = stdOut;
t.standardError = stdErr;
JuliaTask *jt =
[[JuliaTask alloc] initWithTask:t
delegate:self
cleanup:^() {
[[NSFileManager defaultManager]
removeItemAtURL:temporaryDirectoryURL
error:nil];
}];
[_tasks addObject:jt];
reply(jt, stdIn.fileHandleForWriting, stdOut.fileHandleForReading,
stdErr.fileHandleForReading);
}
- (void)taskTerminated:(JuliaTask *_Nonnull)jt {
[_tasks removeObject:jt];
}
@end
|