48
48
#ifdef __APPLE__
49
49
#include < pthread/spawn.h>
50
50
#include " TargetConditionals.h"
51
- #if !TARGET_OS_IPHONE
52
- extern " C" {
53
- // Provided by System.framework's libsystem_kernel interface
54
- extern int __pthread_chdir (const char *path);
55
- extern int __pthread_fchdir (int fd);
56
- }
57
-
58
- // / Set the thread specific working directory to the given path.
59
- int pthread_chdir_np (const char *path)
60
- {
61
- return __pthread_chdir (path);
62
- }
63
-
64
- // / Set the thread specific working directory to that of the given file
65
- // / descriptor. Passing -1 clears the thread specific working directory,
66
- // / returning it to the process level working directory.
67
- int pthread_fchdir_np (int fd)
68
- {
69
- return __pthread_fchdir (fd);
70
- }
71
- #endif
72
51
#endif
73
52
74
53
#ifndef __GLIBC_PREREQ
75
54
#define __GLIBC_PREREQ (maj, min ) 0
76
55
#endif
77
56
78
57
#if !defined(_WIN32) && defined(HAVE_POSIX_SPAWN)
58
+ static bool posix_spawn_file_actions_addchdir_supported () {
59
+ #if (defined(__GLIBC__) && !__GLIBC_PREREQ(2, 29)) || (defined(__OpenBSD__)) || (defined(__ANDROID__) && __ANDROID_API__ < 34) || (defined(__QNX__))
60
+ return false ;
61
+ #else
62
+ return true ;
63
+ #endif
64
+ }
65
+
79
66
// Implementation mostly copied from _CFPosixSpawnFileActionsChdir in swift-corelibs-foundation
80
67
static int posix_spawn_file_actions_addchdir_polyfill (posix_spawn_file_actions_t * __restrict file_actions,
81
68
const char * __restrict path) {
@@ -775,11 +762,16 @@ void llbuild::basic::spawnProcess(
775
762
posix_spawn_file_actions_t fileActions;
776
763
posix_spawn_file_actions_init (&fileActions);
777
764
778
- bool usePosixSpawnChdirFallback = true ;
779
765
const auto workingDir = attr.workingDir .str ();
780
- if (!workingDir.empty () &&
781
- posix_spawn_file_actions_addchdir_polyfill (&fileActions, workingDir.c_str ()) != ENOSYS) {
782
- usePosixSpawnChdirFallback = false ;
766
+ if (!workingDir.empty ()
767
+ && posix_spawn_file_actions_addchdir_supported ()
768
+ && posix_spawn_file_actions_addchdir_polyfill (&fileActions, workingDir.c_str ()) != 0 ) {
769
+ auto result = ProcessResult::makeFailed ();
770
+ delegate.processStarted (ctx, handle, pid);
771
+ delegate.processHadError (ctx, handle, Twine (" failed to set the working directory" ));
772
+ delegate.processFinished (ctx, handle, result);
773
+ completionFn (result);
774
+ return ;
783
775
}
784
776
785
777
#endif
@@ -865,36 +857,6 @@ void llbuild::basic::spawnProcess(
865
857
866
858
int result = 0 ;
867
859
868
- bool workingDirectoryUnsupported = false ;
869
-
870
- #if !defined(_WIN32)
871
- if (usePosixSpawnChdirFallback) {
872
- #if defined(__APPLE__)
873
- thread_local std::string threadWorkingDir;
874
-
875
- if (workingDir.empty ()) {
876
- if (!threadWorkingDir.empty ()) {
877
- pthread_fchdir_np (-1 );
878
- threadWorkingDir.clear ();
879
- }
880
- } else {
881
- if (threadWorkingDir != workingDir) {
882
- if (pthread_chdir_np (workingDir.c_str ()) == -1 ) {
883
- result = errno;
884
- } else {
885
- threadWorkingDir = workingDir;
886
- }
887
- }
888
- }
889
- #else
890
- if (!workingDir.empty ()) {
891
- workingDirectoryUnsupported = true ;
892
- result = -1 ;
893
- }
894
- #endif // if defined(__APPLE__)
895
- }
896
- #endif // else !defined(_WIN32)
897
-
898
860
if (result == 0 ) {
899
861
#if defined(_WIN32)
900
862
auto unicodeEnv = environment.getWindowsEnvp ();
@@ -909,10 +871,47 @@ void llbuild::basic::spawnProcess(
909
871
: (LPWSTR)u16Cwd.data (),
910
872
&startupInfo, &processInfo);
911
873
#else
912
- result =
874
+ // For platforms missing posix_spawn_file_actions_addchdir{_np}, we need to fork in order to thread-safely set the wd
875
+ if (!workingDir.empty ()
876
+ && !posix_spawn_file_actions_addchdir_supported ()) {
877
+ pid_t childPid = fork ();
878
+ switch (childPid) {
879
+ case -1 :
880
+ // Fail
881
+ result = errno;
882
+ break ;
883
+ case 0 :
884
+ // Child
885
+ pthread_sigmask (SIG_BLOCK, &mostSignals, NULL );
886
+ if (chdir (workingDir.c_str ()) != 0 ) {
887
+ _exit (EXIT_FAILURE);
888
+ }
889
+ if (attr.connectToConsole ) {
890
+ dup2 (STDIN_FILENO, STDIN_FILENO);
891
+ dup2 (STDOUT_FILENO, STDOUT_FILENO);
892
+ dup2 (STDERR_FILENO, STDERR_FILENO);
893
+ } else {
894
+ setpgid (0 , 0 );
895
+ dup2 (open (" /dev/null" , O_RDONLY, 0 ), STDIN_FILENO);
896
+ dup2 (outputPipeChildEnd.unsafeDescriptor (), STDOUT_FILENO);
897
+ dup2 (outputPipeChildEnd.unsafeDescriptor (), STDERR_FILENO);
898
+ close (outputPipeChildEnd.unsafeDescriptor ());
899
+ }
900
+ if (attr.controlEnabled ) {
901
+ dup2 (controlPipeChildEnd.unsafeDescriptor (), controlPipeChildEnd.unsafeDescriptor ());
902
+ }
903
+ _exit (execve (args[0 ], const_cast <char **>(args.data ()), const_cast <char * const *>(environment.getEnvp ())));
904
+ default :
905
+ // Parent
906
+ pid = childPid;
907
+ break ;
908
+ }
909
+ } else {
910
+ result =
913
911
posix_spawn (&pid, args[0 ], /* file_actions=*/ &fileActions,
914
912
/* attrp=*/ &attributes, const_cast <char **>(args.data ()),
915
913
const_cast <char * const *>(environment.getEnvp ()));
914
+ }
916
915
#endif
917
916
}
918
917
@@ -925,10 +924,7 @@ void llbuild::basic::spawnProcess(
925
924
#endif
926
925
delegate.processHadError (
927
926
ctx, handle,
928
- workingDirectoryUnsupported
929
- ? Twine (" working-directory unsupported on this platform" )
930
- : Twine (" unable to spawn process '" ) + argsStorage[0 ] + " ' (" + sys::strerror (result) +
931
- " )" );
927
+ Twine (" unable to spawn process '" ) + argsStorage[0 ] + " ' (" + sys::strerror (result) + " )" );
932
928
delegate.processFinished (ctx, handle, processResult);
933
929
pid = (llbuild_pid_t )-1 ;
934
930
} else {
0 commit comments