Skip to content

Commit

Permalink
Implement FileDescriptor.Pipe() (#58)
Browse files Browse the repository at this point in the history
Adds support for pipe(2)
  • Loading branch information
GeorgeLyon authored Sep 27, 2021
1 parent ce8b491 commit 689390f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
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`.
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

0 comments on commit 689390f

Please sign in to comment.