@@ -350,8 +350,8 @@ extension Configuration {
350
350
)
351
351
352
352
internal func preSpawn< Result: ~ Copyable> (
353
- _ work: ( PreSpawnArgs ) throws -> Result
354
- ) throws -> Result {
353
+ _ work: ( PreSpawnArgs ) async throws -> Result
354
+ ) async throws -> Result {
355
355
// Prepare environment
356
356
let env = self . environment. createEnv ( )
357
357
defer {
@@ -378,7 +378,7 @@ extension Configuration {
378
378
if let groupsValue = self . platformOptions. supplementaryGroups {
379
379
supplementaryGroups = groupsValue
380
380
}
381
- return try work (
381
+ return try await work (
382
382
(
383
383
env: env,
384
384
uidPtr: uidPtr,
@@ -415,11 +415,24 @@ internal typealias PlatformFileDescriptor = CInt
415
415
416
416
#if !canImport(Darwin)
417
417
extension Configuration {
418
+
419
+ // @unchecked Sendable because we need to capture UnsafePointers
420
+ // to send to another thread. While UnsafePointers are not
421
+ // Sendable, we are not mutating them -- we only need these type
422
+ // for C interface.
423
+ internal struct SpawnContext : @unchecked Sendable {
424
+ let argv : [ UnsafeMutablePointer < CChar > ? ]
425
+ let env : [ UnsafeMutablePointer < CChar > ? ]
426
+ let uidPtr : UnsafeMutablePointer < uid_t > ?
427
+ let gidPtr : UnsafeMutablePointer < gid_t > ?
428
+ let processGroupIDPtr : UnsafeMutablePointer < gid_t > ?
429
+ }
430
+
418
431
internal func spawn(
419
432
withInput inputPipe: consuming CreatedPipe ,
420
433
outputPipe: consuming CreatedPipe ,
421
434
errorPipe: consuming CreatedPipe
422
- ) throws -> SpawnResult {
435
+ ) async throws -> SpawnResult {
423
436
// Ensure the waiter thread is running.
424
437
#if os(Linux) || os(Android)
425
438
_setupMonitorSignalHandler ( )
@@ -434,7 +447,7 @@ extension Configuration {
434
447
var outputPipeBox : CreatedPipe ? = consume outputPipe
435
448
var errorPipeBox : CreatedPipe ? = consume errorPipe
436
449
437
- return try self . preSpawn { args throws -> SpawnResult in
450
+ return try await self . preSpawn { args throws -> SpawnResult in
438
451
let ( env, uidPtr, gidPtr, supplementaryGroups) = args
439
452
440
453
var _inputPipe = inputPipeBox. take ( ) !
@@ -472,27 +485,34 @@ extension Configuration {
472
485
]
473
486
474
487
// Spawn
475
- var pid : pid_t = 0
476
- var processDescriptor : PlatformFileDescriptor = - 1
477
- let spawnError : CInt = possibleExecutablePath. withCString { exePath in
478
- return ( self . workingDirectory? . string) . withOptionalCString { workingDir in
479
- return supplementaryGroups. withOptionalUnsafeBufferPointer { sgroups in
480
- return fileDescriptors. withUnsafeBufferPointer { fds in
481
- return _subprocess_fork_exec (
482
- & pid,
483
- & processDescriptor,
484
- exePath,
485
- workingDir,
486
- fds. baseAddress!,
487
- argv,
488
- env,
489
- uidPtr,
490
- gidPtr,
491
- processGroupIDPtr,
492
- CInt ( supplementaryGroups? . count ?? 0 ) ,
493
- sgroups? . baseAddress,
494
- self . platformOptions. createSession ? 1 : 0
495
- )
488
+ let spawnContext = SpawnContext (
489
+ argv: argv, env: env, uidPtr: uidPtr, gidPtr: gidPtr, processGroupIDPtr: processGroupIDPtr
490
+ )
491
+ let ( pid, processDescriptor, spawnError) = try await runOnBackgroundThread {
492
+ return possibleExecutablePath. withCString { exePath in
493
+ return ( self . workingDirectory? . string) . withOptionalCString { workingDir in
494
+ return supplementaryGroups. withOptionalUnsafeBufferPointer { sgroups in
495
+ return fileDescriptors. withUnsafeBufferPointer { fds in
496
+ var pid : pid_t = 0
497
+ var processDescriptor : PlatformFileDescriptor = - 1
498
+
499
+ let rc = _subprocess_fork_exec (
500
+ & pid,
501
+ & processDescriptor,
502
+ exePath,
503
+ workingDir,
504
+ fds. baseAddress!,
505
+ spawnContext. argv,
506
+ spawnContext. env,
507
+ spawnContext. uidPtr,
508
+ spawnContext. gidPtr,
509
+ spawnContext. processGroupIDPtr,
510
+ CInt ( supplementaryGroups? . count ?? 0 ) ,
511
+ sgroups? . baseAddress,
512
+ self . platformOptions. createSession ? 1 : 0
513
+ )
514
+ return ( pid, processDescriptor, rc)
515
+ }
496
516
}
497
517
}
498
518
}
@@ -658,51 +678,6 @@ extension PlatformOptions: CustomStringConvertible, CustomDebugStringConvertible
658
678
return self . description ( withIndent: 0 )
659
679
}
660
680
}
661
-
662
- // Special keys used in Error's user dictionary
663
- extension String {
664
- static let debugDescriptionErrorKey = " DebugDescription "
665
- }
666
-
667
- internal func pthread_create( _ body: @Sendable @escaping ( ) -> ( ) ) throws ( SubprocessError. UnderlyingError) -> pthread_t {
668
- final class Context {
669
- let body : @Sendable ( ) -> ( )
670
- init ( body: @Sendable @escaping ( ) -> Void ) {
671
- self . body = body
672
- }
673
- }
674
- #if canImport(Glibc) || canImport(Musl)
675
- func proc( _ context: UnsafeMutableRawPointer ? ) -> UnsafeMutableRawPointer ? {
676
- ( Unmanaged < AnyObject > . fromOpaque ( context!) . takeRetainedValue ( ) as! Context ) . body ( )
677
- return nil
678
- }
679
- #elseif canImport(Bionic)
680
- func proc( _ context: UnsafeMutableRawPointer ) -> UnsafeMutableRawPointer {
681
- ( Unmanaged < AnyObject > . fromOpaque ( context) . takeRetainedValue ( ) as! Context ) . body ( )
682
- return context
683
- }
684
- #endif
685
- #if (os(Linux) && canImport(Glibc)) || canImport(Bionic)
686
- var thread = pthread_t ( )
687
- #else
688
- var thread : pthread_t ?
689
- #endif
690
- let rc = pthread_create (
691
- & thread,
692
- nil ,
693
- proc,
694
- Unmanaged . passRetained ( Context ( body: body) ) . toOpaque ( )
695
- )
696
- if rc != 0 {
697
- throw SubprocessError . UnderlyingError ( rawValue: rc)
698
- }
699
- #if (os(Linux) && canImport(Glibc)) || canImport(Bionic)
700
- return thread
701
- #else
702
- return thread!
703
- #endif
704
- }
705
-
706
681
#endif // !canImport(Darwin)
707
682
708
683
extension ProcessIdentifier {
0 commit comments