Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement FileDescriptor.Pipe() #58

Merged
merged 17 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
23 changes: 23 additions & 0 deletions Sources/System/FileOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,27 @@ extension FileDescriptor {
public func dup2() throws -> FileDescriptor {
fatalError("Not implemented")
}

#if !os(Windows)
/// Create a pipe, a unidirectional data channel which can be used for interprocess communication.
///
/// - Returns: The pair of file descriptors.
///
/// The corresponding C function is `pipe`.
@_alwaysEmitIntoClient
// @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
public static func pipe() throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) {
try _pipe().get()
}

@usableFromInline
internal static func _pipe() -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> {
var fds: (Int32, Int32) = (-1, -1)
return withUnsafeMutablePointer(to: &fds) { pointer in
valueOrErrno(retryOnInterrupt: false) {
system_pipe(UnsafeMutableRawPointer(pointer).assumingMemoryBound(to: Int32.self))
}
}.map { _ in (.init(rawValue: fds.0), .init(rawValue: fds.1)) }
}
#endif
}
8 changes: 8 additions & 0 deletions Sources/System/Internals/Syscalls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,11 @@ internal func system_dup2(_ fd: Int32, _ fd2: Int32) -> Int32 {
#endif
return dup2(fd, fd2)
}
#if !os(Windows)
internal func system_pipe(_ fds: UnsafeMutablePointer<Int32>) -> CInt {
#if ENABLE_MOCKING
if mockingEnabled { return _mock(fds) }
#endif
return pipe(fds)
}
#endif
21 changes: 21 additions & 0 deletions Tests/SystemTests/FileOperationsTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ final class FileOperationsTest: XCTestCase {
func testHelpers() {
// TODO: Test writeAll, writeAll(toAbsoluteOffset), closeAfter
}

#if !os(Windows)
func testAdHocPipe() throws {
// Ad-hoc test testing `Pipe` functionality.
// We cannot test `Pipe` using `MockTestCase` because it calls `pipe` with a pointer to an array local to the `Pipe`, the address of which we do not know prior to invoking `Pipe`.
Copy link
Contributor

Choose a reason for hiding this comment

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

We probably do (not gonna hold up this PR for it though) want to allow for mock testing of such stack local pointers. We'd probably have a variant that we'd pass in an array and it would compare the contents.

let pipe = try FileDescriptor.pipe()
try pipe.readEnd.closeAfter {
try pipe.writeEnd.closeAfter {
var abc = "abc"
try abc.withUTF8 {
_ = try pipe.writeEnd.write(UnsafeRawBufferPointer($0))
}
let readLen = 3
let readBytes = try Array<UInt8>(unsafeUninitializedCapacity: readLen) { buf, count in
count = try pipe.readEnd.read(into: UnsafeMutableRawBufferPointer(buf))
}
XCTAssertEqual(readBytes, Array(abc.utf8))
}
}
}
#endif

func testAdHocOpen() {
// Ad-hoc test touching a file system.
Expand Down