Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Foundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
5B13B3431C582D4C00651CE2 /* TestNSScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844DC3321C17584F005611F9 /* TestNSScanner.swift */; };
5B13B3441C582D4C00651CE2 /* TestNSSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA66F6411BF1619600136161 /* TestNSSet.swift */; };
5B13B3451C582D4C00651CE2 /* TestNSString.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA66F6421BF1619600136161 /* TestNSString.swift */; };
5B13B3461C582D4C00651CE2 /* TestNSTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6F17941C48631C00935030 /* TestNSTask.swift */; };
5B13B3461C582D4C00651CE2 /* TestProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6F17941C48631C00935030 /* TestProcess.swift */; };
5B13B3471C582D4C00651CE2 /* TestNSThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5835F31C20C9B500C81317 /* TestNSThread.swift */; };
5B13B3481C582D4C00651CE2 /* TestNSTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D6C9EE1C1DFE9500DEF583 /* TestNSTimer.swift */; };
5B13B3491C582D4C00651CE2 /* TestNSTimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BA558D1C16F90900F48C54 /* TestNSTimeZone.swift */; };
Expand Down Expand Up @@ -383,7 +383,7 @@
EADE0BB51BD15E0000C49C64 /* NSScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B771BD15DFF00C49C64 /* NSScanner.swift */; };
EADE0BB61BD15E0000C49C64 /* NSSortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B781BD15DFF00C49C64 /* NSSortDescriptor.swift */; };
EADE0BB71BD15E0000C49C64 /* NSStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B791BD15DFF00C49C64 /* NSStream.swift */; };
EADE0BB81BD15E0000C49C64 /* NSTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B7A1BD15DFF00C49C64 /* NSTask.swift */; };
EADE0BB81BD15E0000C49C64 /* Process.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B7A1BD15DFF00C49C64 /* Process.swift */; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not see a build.py alteration for this; might be a problem on linux builds (which is a pre-requisite to merging)

EADE0BB91BD15E0000C49C64 /* NSTextCheckingResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B7B1BD15DFF00C49C64 /* NSTextCheckingResult.swift */; };
EADE0BBB1BD15E0000C49C64 /* NSURLAuthenticationChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B7D1BD15DFF00C49C64 /* NSURLAuthenticationChallenge.swift */; };
EADE0BBC1BD15E0000C49C64 /* NSURLCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADE0B7E1BD15DFF00C49C64 /* NSURLCache.swift */; };
Expand Down Expand Up @@ -657,7 +657,7 @@
5B628EDE1D1C995C00CA9570 /* NSMeasurementFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMeasurementFormatter.swift; sourceTree = "<group>"; };
5B6F17921C48631C00935030 /* TestNSNull.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNull.swift; sourceTree = "<group>"; };
5B6F17931C48631C00935030 /* TestNSNumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSNumberFormatter.swift; sourceTree = "<group>"; };
5B6F17941C48631C00935030 /* TestNSTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSTask.swift; sourceTree = "<group>"; };
5B6F17941C48631C00935030 /* TestProcess.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = TestProcess.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5B6F17951C48631C00935030 /* TestNSXMLDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSXMLDocument.swift; sourceTree = "<group>"; };
5B6F17961C48631C00935030 /* TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
5B7818591D6CB5CD004A01F2 /* CGFloat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGFloat.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -848,7 +848,7 @@
EADE0B771BD15DFF00C49C64 /* NSScanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSScanner.swift; sourceTree = "<group>"; };
EADE0B781BD15DFF00C49C64 /* NSSortDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSSortDescriptor.swift; sourceTree = "<group>"; };
EADE0B791BD15DFF00C49C64 /* NSStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSStream.swift; sourceTree = "<group>"; };
EADE0B7A1BD15DFF00C49C64 /* NSTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSTask.swift; sourceTree = "<group>"; };
EADE0B7A1BD15DFF00C49C64 /* Process.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Process.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
EADE0B7B1BD15DFF00C49C64 /* NSTextCheckingResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSTextCheckingResult.swift; sourceTree = "<group>"; };
EADE0B7D1BD15DFF00C49C64 /* NSURLAuthenticationChallenge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLAuthenticationChallenge.swift; sourceTree = "<group>"; };
EADE0B7E1BD15DFF00C49C64 /* NSURLCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLCache.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1361,7 +1361,7 @@
844DC3321C17584F005611F9 /* TestNSScanner.swift */,
EA66F6411BF1619600136161 /* TestNSSet.swift */,
EA66F6421BF1619600136161 /* TestNSString.swift */,
5B6F17941C48631C00935030 /* TestNSTask.swift */,
5B6F17941C48631C00935030 /* TestProcess.swift */,
5FE52C941D147D1C00F7D270 /* TestNSTextCheckingResult.swift */,
5E5835F31C20C9B500C81317 /* TestNSThread.swift */,
61D6C9EE1C1DFE9500DEF583 /* TestNSTimer.swift */,
Expand Down Expand Up @@ -1635,7 +1635,7 @@
children = (
EADE0B5D1BD15DFF00C49C64 /* NSFileHandle.swift */,
EADE0B5E1BD15DFF00C49C64 /* NSFileManager.swift */,
EADE0B7A1BD15DFF00C49C64 /* NSTask.swift */,
EADE0B7A1BD15DFF00C49C64 /* Process.swift */,
5BDC3F2F1BCC5DCB00ED97BB /* NSBundle.swift */,
5BDC3F411BCC5DCB00ED97BB /* NSProcessInfo.swift */,
5BDC3F471BCC5DCB00ED97BB /* NSThread.swift */,
Expand Down Expand Up @@ -2054,7 +2054,7 @@
6EB768281D18C12C00D4B719 /* UUID.swift in Sources */,
5B1FD9D41D6D16580080E83C /* Configuration.swift in Sources */,
5BF7AEA51BCD51F9008F214A /* NSCalendar.swift in Sources */,
EADE0BB81BD15E0000C49C64 /* NSTask.swift in Sources */,
EADE0BB81BD15E0000C49C64 /* Process.swift in Sources */,
5BF7AEB31BCD51F9008F214A /* NSObjCRuntime.swift in Sources */,
5BD31D3F1D5D19D600563814 /* Dictionary.swift in Sources */,
5B94E8821C430DE70055C035 /* NSStringAPI.swift in Sources */,
Expand Down Expand Up @@ -2267,7 +2267,7 @@
5B13B3521C582D4C00651CE2 /* TestNSValue.swift in Sources */,
5B13B3311C582D4C00651CE2 /* TestNSIndexPath.swift in Sources */,
5B13B3271C582D4C00651CE2 /* TestNSArray.swift in Sources */,
5B13B3461C582D4C00651CE2 /* TestNSTask.swift in Sources */,
5B13B3461C582D4C00651CE2 /* TestProcess.swift in Sources */,
555683BD1C1250E70041D4C6 /* TestNSUserDefaults.swift in Sources */,
7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */,
);
Expand Down
98 changes: 49 additions & 49 deletions Foundation/NSTask.swift → Foundation/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import CoreFoundation
import Glibc
#endif

extension Task {
extension Process {
public enum TerminationReason : Int {
case exit
case uncaughtSignal
Expand Down Expand Up @@ -72,27 +72,27 @@ private func runloopIsEqual(_ a : UnsafeRawPointer?, _ b : UnsafeRawPointer?) ->
}


// Equal method for task in run loop source
private func nstaskIsEqual(_ a : UnsafeRawPointer?, _ b : UnsafeRawPointer?) -> _DarwinCompatibleBoolean {
// Equal method for process in run loop source
private func processIsEqual(_ a : UnsafeRawPointer?, _ b : UnsafeRawPointer?) -> _DarwinCompatibleBoolean {

let unmanagedTaskA = Unmanaged<AnyObject>.fromOpaque(a!)
guard let taskA = unmanagedTaskA.takeUnretainedValue() as? Task else {
let unmanagedProcessA = Unmanaged<AnyObject>.fromOpaque(a!)
guard let processA = unmanagedProcessA.takeUnretainedValue() as? Process else {
return false
}

let unmanagedTaskB = Unmanaged<AnyObject>.fromOpaque(a!)
guard let taskB = unmanagedTaskB.takeUnretainedValue() as? Task else {
let unmanagedProcessB = Unmanaged<AnyObject>.fromOpaque(a!)
guard let processB = unmanagedProcessB.takeUnretainedValue() as? Process else {
return false
}

guard taskA == taskB else {
guard processA == processB else {
return false
}

return true
}

open class Task: NSObject {
open class Process: NSObject {
private static func setup() {
struct Once {
static var done = false
Expand Down Expand Up @@ -124,7 +124,7 @@ open class Task: NSObject {
}

managerThreadRunLoop?.run()
fatalError("NSTask manager run loop exited unexpectedly; it should run forever once initialized")
fatalError("Process manager run loop exited unexpectedly; it should run forever once initialized")
}
thread.start()
managerThreadRunLoopIsRunningCondition.lock()
Expand All @@ -137,11 +137,11 @@ open class Task: NSObject {
}
}

// Create an NSTask which can be run at a later time
// An NSTask can only be run once. Subsequent attempts to
// run an NSTask will raise.
// Upon task death a notification will be sent
// { Name = NSTaskDidTerminateNotification; object = task; }
// Create an Process which can be run at a later time
// An Process can only be run once. Subsequent attempts to
// run an Process will raise.
// Upon process death a notification will be sent
// { Name = ProcessDidTerminateNotification; object = process; }
//

public override init() {
Expand All @@ -156,19 +156,19 @@ open class Task: NSObject {
open var currentDirectoryPath: String = FileManager.default.currentDirectoryPath

// standard I/O channels; could be either an NSFileHandle or an NSPipe
open var standardInput: AnyObject? {
open var standardInput: Any? {
willSet {
precondition(newValue is Pipe || newValue is FileHandle,
"standardInput must be either NSPipe or NSFileHandle")
}
}
open var standardOutput: AnyObject? {
open var standardOutput: Any? {
willSet {
precondition(newValue is Pipe || newValue is FileHandle,
"standardOutput must be either NSPipe or NSFileHandle")
}
}
open var standardError: AnyObject? {
open var standardError: Any? {
willSet {
precondition(newValue is Pipe || newValue is FileHandle,
"standardError must be either NSPipe or NSFileHandle")
Expand All @@ -189,7 +189,7 @@ open class Task: NSObject {

// Dispatch the manager thread if it isn't already running

Task.setup()
Process.setup()

// Ensure that the launch path is set

Expand Down Expand Up @@ -251,14 +251,14 @@ open class Task: NSObject {
let socket = CFSocketCreateWithNative( nil, taskSocketPair[0], CFOptionFlags(kCFSocketDataCallBack), {
(socket, type, address, data, info ) in

let task: Task = NSObject.unretainedReference(info!)
let process: Process = NSObject.unretainedReference(info!)

task.processLaunchedCondition.lock()
while task.running == false {
task.processLaunchedCondition.wait()
process.processLaunchedCondition.lock()
while process.isRunning == false {
process.processLaunchedCondition.wait()
}

task.processLaunchedCondition.unlock()
process.processLaunchedCondition.unlock()

var exitCode : Int32 = 0
#if CYGWIN
Expand All @@ -271,31 +271,31 @@ open class Task: NSObject {

repeat {
#if CYGWIN
waitResult = waitpid( task.processIdentifier, exitCodePtrWrapper, 0)
waitResult = waitpid( process.processIdentifier, exitCodePtrWrapper, 0)
#else
waitResult = waitpid( task.processIdentifier, &exitCode, 0)
waitResult = waitpid( process.processIdentifier, &exitCode, 0)
#endif
} while ( (waitResult == -1) && (errno == EINTR) )

task.terminationStatus = WEXITSTATUS( exitCode )
process.terminationStatus = WEXITSTATUS( exitCode )

// If a termination handler has been set, invoke it on a background thread

if task.terminationHandler != nil {
if process.terminationHandler != nil {
let thread = Thread {
task.terminationHandler!(task)
process.terminationHandler!(process)
}
thread.start()
}

// Set the running flag to false

task.running = false
process.isRunning = false

// Invalidate the source and wake up the run loop, if it's available

CFRunLoopSourceInvalidate(task.runLoopSource)
if let runLoop = task.runLoop {
CFRunLoopSourceInvalidate(process.runLoopSource)
if let runLoop = process.runLoop {
CFRunLoopWakeUp(runLoop._cfRunLoop)
}

Expand Down Expand Up @@ -384,7 +384,7 @@ open class Task: NSObject {
retain: { return runLoopSourceRetain($0) },
release: { runLoopSourceRelease($0) },
copyDescription: nil,
equal: { return nstaskIsEqual($0, $1) },
equal: { return processIsEqual($0, $1) },
hash: nil,
schedule: nil,
cancel: nil,
Expand All @@ -395,7 +395,7 @@ open class Task: NSObject {
runLoopContext.version = 0
runLoopContext.retain = runLoopSourceRetain
runLoopContext.release = runLoopSourceRelease
runLoopContext.equal = nstaskIsEqual
runLoopContext.equal = processIsEqual
runLoopContext.perform = emptyRunLoopCallback
self.withUnretainedReference {
(refPtr: UnsafeMutablePointer<UInt8>) in
Expand All @@ -406,7 +406,7 @@ open class Task: NSObject {
self.runLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &runLoopSourceContext!)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode)

running = true
isRunning = true

self.processIdentifier = pid

Expand All @@ -422,42 +422,42 @@ open class Task: NSObject {

// status
open private(set) var processIdentifier: Int32 = -1
open private(set) var running: Bool = false
open private(set) var isRunning: Bool = false

open private(set) var terminationStatus: Int32 = 0
open var terminationReason: TerminationReason { NSUnimplemented() }

/*
A block to be invoked when the process underlying the NSTask terminates. Setting the block to nil is valid, and stops the previous block from being invoked, as long as it hasn't started in any way. The NSTask is passed as the argument to the block so the block does not have to capture, and thus retain, it. The block is copied when set. Only one termination handler block can be set at any time. The execution context in which the block is invoked is undefined. If the NSTask has already finished, the block is executed immediately/soon (not necessarily on the current thread). If a terminationHandler is set on an NSTask, the NSTaskDidTerminateNotification notification is not posted for that task. Also note that -waitUntilExit won't wait until the terminationHandler has been fully executed. You cannot use this property in a concrete subclass of NSTask which hasn't been updated to include an implementation of the storage and use of it.
A block to be invoked when the process underlying the Process terminates. Setting the block to nil is valid, and stops the previous block from being invoked, as long as it hasn't started in any way. The Process is passed as the argument to the block so the block does not have to capture, and thus retain, it. The block is copied when set. Only one termination handler block can be set at any time. The execution context in which the block is invoked is undefined. If the Process has already finished, the block is executed immediately/soon (not necessarily on the current thread). If a terminationHandler is set on an Process, the ProcessDidTerminateNotification notification is not posted for that process. Also note that -waitUntilExit won't wait until the terminationHandler has been fully executed. You cannot use this property in a concrete subclass of Process which hasn't been updated to include an implementation of the storage and use of it.
*/
open var terminationHandler: ((Task) -> Void)?
open var qualityOfService: NSQualityOfService = .default // read-only after the task is launched
open var terminationHandler: ((Process) -> Void)?
open var qualityOfService: NSQualityOfService = .default // read-only after the process is launched
}

extension Task {
extension Process {

// convenience; create and launch
open class func launchedTaskWithLaunchPath(_ path: String, arguments: [String]) -> Task {
let task = Task()
task.launchPath = path
task.arguments = arguments
task.launch()
open class func launchedProcess(launchPath path: String, arguments: [String]) -> Process {
let process = Process()
process.launchPath = path
process.arguments = arguments
process.launch()

return task
return process
}

// poll the runLoop in defaultMode until task completes
// poll the runLoop in defaultMode until process completes
open func waitUntilExit() {

repeat {

} while( self.running == true && RunLoop.current.run(mode: .defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.05)) )
} while( self.isRunning == true && RunLoop.current.run(mode: .defaultRunLoopMode, before: Date(timeIntervalSinceNow: 0.05)) )

self.runLoop = nil
}
}

public let NSTaskDidTerminateNotification: String = "NSTaskDidTerminateNotification"
public let didTerminateNotification = NSNotification.Name(rawValue: "NSTaskDidTerminateNotification")
Copy link
Member

@ikesyo ikesyo Nov 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still defined as a global constant, not as a static property of Process.


private func posix(_ code: Int32) {
switch code {
Expand Down
Loading