-
Notifications
You must be signed in to change notification settings - Fork 126
Add overloads to cover dup3 and pipe2 POSIX APIs #266
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
extern int csystem_posix_pipe2(int fildes[2], int flag); | ||
extern int csystem_posix_dup3(int fildes, int fildes2, int flag); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -403,17 +403,61 @@ extension FileDescriptor { | |
as target: FileDescriptor? = nil, | ||
retryOnInterrupt: Bool = true | ||
) throws -> FileDescriptor { | ||
try _duplicate(as: target, retryOnInterrupt: retryOnInterrupt).get() | ||
try _duplicate(as: target, options: 0, retryOnInterrupt: retryOnInterrupt).get() | ||
} | ||
|
||
/// Duplicates this file descriptor and return the newly created copy. | ||
/// | ||
/// - Parameters: | ||
/// - `target`: The desired target file descriptor. | ||
/// - `options`: The behavior for creating the target file descriptor. | ||
/// - retryOnInterrupt: Whether to retry the write operation | ||
/// if it throws ``Errno/interrupted``. The default is `true`. | ||
/// Pass `false` to try only once and throw an error upon interruption. | ||
/// - Returns: The new file descriptor. | ||
/// | ||
/// If the `target` descriptor is already in use, then it is first | ||
/// deallocated as if a close(2) call had been done first. | ||
/// | ||
/// File descriptors are merely references to some underlying system resource. | ||
/// The system does not distinguish between the original and the new file | ||
/// descriptor in any way. For example, read, write and seek operations on | ||
/// one of them also affect the logical file position in the other, and | ||
/// append mode, non-blocking I/O and asynchronous I/O options are shared | ||
/// between the references. If a separate pointer into the file is desired, | ||
/// a different object reference to the file must be obtained by issuing an | ||
/// additional call to `open`. | ||
/// | ||
/// However, each file descriptor maintains its own close-on-exec flag. | ||
/// | ||
/// | ||
/// The corresponding C function is `dup3`. | ||
@_alwaysEmitIntoClient | ||
@available(Windows, unavailable) | ||
@available(macOS, unavailable) | ||
@available(iOS, unavailable) | ||
@available(tvOS, unavailable) | ||
@available(watchOS, unavailable) | ||
@available(visionOS, unavailable) | ||
public func duplicate( | ||
as target: FileDescriptor, | ||
options: DuplicateOptions, | ||
retryOnInterrupt: Bool = true | ||
) throws -> FileDescriptor { | ||
try _duplicate(as: target, options: options.rawValue, retryOnInterrupt: retryOnInterrupt).get() | ||
} | ||
|
||
@available(System 0.0.2, *) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A |
||
@usableFromInline | ||
internal func _duplicate( | ||
as target: FileDescriptor?, | ||
options: Int32, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't remove the old |
||
retryOnInterrupt: Bool | ||
) throws -> Result<FileDescriptor, Errno> { | ||
valueOrErrno(retryOnInterrupt: retryOnInterrupt) { | ||
if let target = target { | ||
if options != 0 { | ||
return system_dup3(self.rawValue, target.rawValue, options) | ||
} | ||
return system_dup2(self.rawValue, target.rawValue) | ||
} | ||
return system_dup(self.rawValue) | ||
|
@@ -431,6 +475,12 @@ extension FileDescriptor { | |
public func dup2() throws -> FileDescriptor { | ||
fatalError("Not implemented") | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
@available(*, unavailable, renamed: "duplicate") | ||
public func dup3() throws -> FileDescriptor { | ||
fatalError("Not implemented") | ||
} | ||
} | ||
#endif | ||
|
||
|
@@ -445,21 +495,48 @@ extension FileDescriptor { | |
@_alwaysEmitIntoClient | ||
@available(System 1.1.0, *) | ||
public static func pipe() throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) { | ||
try _pipe().get() | ||
try _pipe(options: 0).get() | ||
} | ||
|
||
/// Creates a unidirectional data channel, which can be used for interprocess communication. | ||
/// | ||
/// - Parameters: | ||
/// - options: The behavior for creating the pipe. | ||
/// | ||
/// - Returns: The pair of file descriptors. | ||
/// | ||
/// The corresponding C function is `pipe2`. | ||
@_alwaysEmitIntoClient | ||
@available(Windows, unavailable) | ||
@available(macOS, unavailable) | ||
@available(iOS, unavailable) | ||
@available(tvOS, unavailable) | ||
@available(watchOS, unavailable) | ||
@available(visionOS, unavailable) | ||
public static func pipe(options: PipeOptions) throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) { | ||
try _pipe(options: options.rawValue).get() | ||
} | ||
|
||
@available(System 1.1.0, *) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above, @usableFromInline symbols require availability. |
||
@usableFromInline | ||
internal static func _pipe() -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> { | ||
internal static func _pipe(options: Int32) -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As above. |
||
var fds: (Int32, Int32) = (-1, -1) | ||
return withUnsafeMutablePointer(to: &fds) { pointer in | ||
pointer.withMemoryRebound(to: Int32.self, capacity: 2) { fds in | ||
valueOrErrno(retryOnInterrupt: false) { | ||
system_pipe(fds) | ||
if options != 0 { | ||
return system_pipe2(fds, options) | ||
} | ||
return system_pipe(fds) | ||
}.map { _ in (.init(rawValue: fds[0]), .init(rawValue: fds[1])) } | ||
} | ||
} | ||
} | ||
|
||
@_alwaysEmitIntoClient | ||
@available(*, unavailable, renamed: "pipe") | ||
public func pipe2() throws -> FileDescriptor { | ||
fatalError("Not implemented") | ||
} | ||
} | ||
#endif | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The package version that will include this drops support for Swift toolchains older than 6.0. We could therefore make these
@_aEIC
entry points use typed throws, i.e.throws(ErrNo)
.