@@ -403,17 +403,62 @@ extension FileDescriptor {
403
403
as target: FileDescriptor ? = nil ,
404
404
retryOnInterrupt: Bool = true
405
405
) throws -> FileDescriptor {
406
- try _duplicate ( as: target, retryOnInterrupt: retryOnInterrupt) . get ( )
406
+ try _duplicate ( as: target, options: [ ] , retryOnInterrupt: retryOnInterrupt) . get ( )
407
+ }
408
+
409
+ /// Duplicates this file descriptor and return the newly created copy.
410
+ ///
411
+ /// - Parameters:
412
+ /// - `target`: The desired target file descriptor.
413
+ /// - `options`: The behavior for creating the target file descriptor.
414
+ /// - retryOnInterrupt: Whether to retry the write operation
415
+ /// if it throws ``Errno/interrupted``. The default is `true`.
416
+ /// Pass `false` to try only once and throw an error upon interruption.
417
+ /// - Returns: The new file descriptor.
418
+ ///
419
+ /// If the `target` descriptor is already in use, then it is first
420
+ /// deallocated as if a close(2) call had been done first.
421
+ ///
422
+ /// File descriptors are merely references to some underlying system resource.
423
+ /// The system does not distinguish between the original and the new file
424
+ /// descriptor in any way. For example, read, write and seek operations on
425
+ /// one of them also affect the logical file position in the other, and
426
+ /// append mode, non-blocking I/O and asynchronous I/O options are shared
427
+ /// between the references. If a separate pointer into the file is desired,
428
+ /// a different object reference to the file must be obtained by issuing an
429
+ /// additional call to `open`.
430
+ ///
431
+ /// However, each file descriptor maintains its own close-on-exec flag.
432
+ ///
433
+ ///
434
+ /// The corresponding C function is `dup3`.
435
+ @_alwaysEmitIntoClient
436
+ @available ( Windows, unavailable)
437
+ @available ( macOS, unavailable)
438
+ @available ( iOS, unavailable)
439
+ @available ( tvOS, unavailable)
440
+ @available ( watchOS, unavailable)
441
+ @available ( visionOS, unavailable)
442
+ public func duplicate(
443
+ as target: FileDescriptor ,
444
+ options: DuplicateOptions ,
445
+ retryOnInterrupt: Bool = true
446
+ ) throws -> FileDescriptor {
447
+ try _duplicate ( as: target, options: options, retryOnInterrupt: retryOnInterrupt) . get ( )
407
448
}
408
449
409
450
@available ( System 0 . 0 . 2 , * )
410
451
@usableFromInline
411
452
internal func _duplicate(
412
453
as target: FileDescriptor ? ,
454
+ options: DuplicateOptions ,
413
455
retryOnInterrupt: Bool
414
456
) throws -> Result < FileDescriptor , Errno > {
415
457
valueOrErrno ( retryOnInterrupt: retryOnInterrupt) {
416
458
if let target = target {
459
+ if !options. isEmpty {
460
+ return system_dup3 ( self . rawValue, target. rawValue, options. rawValue)
461
+ }
417
462
return system_dup2 ( self . rawValue, target. rawValue)
418
463
}
419
464
return system_dup ( self . rawValue)
@@ -431,6 +476,12 @@ extension FileDescriptor {
431
476
public func dup2( ) throws -> FileDescriptor {
432
477
fatalError ( " Not implemented " )
433
478
}
479
+
480
+ @_alwaysEmitIntoClient
481
+ @available ( * , unavailable, renamed: " duplicate " )
482
+ public func dup3( ) throws -> FileDescriptor {
483
+ fatalError ( " Not implemented " )
484
+ }
434
485
}
435
486
#endif
436
487
@@ -445,21 +496,49 @@ extension FileDescriptor {
445
496
@_alwaysEmitIntoClient
446
497
@available ( System 1 . 1 . 0 , * )
447
498
public static func pipe( ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
448
- try _pipe ( ) . get ( )
499
+ try _pipe ( options: [ ] ) . get ( )
500
+ }
501
+
502
+ /// Creates a unidirectional data channel, which can be used for interprocess communication.
503
+ ///
504
+ /// - Parameters:
505
+ /// - options: The behavior for creating the pipe.
506
+ ///
507
+ /// - Returns: The pair of file descriptors.
508
+ ///
509
+ /// The corresponding C function is `pipe2`.
510
+ @_alwaysEmitIntoClient
511
+ @available ( Windows, unavailable)
512
+ @available ( macOS, unavailable)
513
+ @available ( iOS, unavailable)
514
+ @available ( tvOS, unavailable)
515
+ @available ( watchOS, unavailable)
516
+ @available ( visionOS, unavailable)
517
+ public static func pipe( options: PipeOptions ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
518
+ try _pipe ( options: options) . get ( )
449
519
}
450
520
451
521
@available ( System 1 . 1 . 0 , * )
452
522
@usableFromInline
453
- internal static func _pipe( ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
523
+ internal static func _pipe( options : PipeOptions ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
454
524
var fds : ( Int32 , Int32 ) = ( - 1 , - 1 )
455
525
return withUnsafeMutablePointer ( to: & fds) { pointer in
456
526
pointer. withMemoryRebound ( to: Int32 . self, capacity: 2 ) { fds in
457
527
valueOrErrno ( retryOnInterrupt: false ) {
458
- system_pipe ( fds)
528
+ if !options. isEmpty {
529
+ return system_pipe2 ( fds, options. rawValue)
530
+ }
531
+ return system_pipe ( fds)
459
532
} . map { _ in ( . init( rawValue: fds [ 0 ] ) , . init( rawValue: fds [ 1 ] ) ) }
460
533
}
461
534
}
462
535
}
536
+
537
+ @_alwaysEmitIntoClient
538
+ @available ( * , unavailable, renamed: " pipe " )
539
+ public func pipe2( ) throws -> FileDescriptor {
540
+ fatalError ( " Not implemented " )
541
+ }
463
542
}
464
543
#endif
465
544
0 commit comments