Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -891,21 +891,30 @@ *-*-msdosdjgpp*) have_processes="no" ;; *) AC_CHECK_FUNCS([fork dup2 execvp kill _exit], [ - if test x"$ac_cv_func_fork" = x"yes" \ + AS_IF([test x"$ac_cv_func_fork" = x"yes" \ -a x"$ac_cv_func_pipe" = x"yes" \ -a x"$ac_cv_func_dup2" = x"yes" \ -a x"$ac_cv_func_execvp" = x"yes" \ -a x"$ac_cv_func_kill" = x"yes" \ - -a x"$ac_cv_func__exit" = x"yes"; then + -a x"$ac_cv_func__exit" = x"yes"], [ have_processes="yes" - fi + ]) ], [ break ]) + + AC_CHECK_FUNCS(posix_spawnp) + + AS_IF([test x"$ac_cv_func_posix_spawnp" = x"yes" \ + -a x"$ac_cv_func_kill" = x"yes"], [ + have_processes="yes" + + AC_CHECK_HEADERS(spawn.h) + ]) ;; esac AS_IF([test x"$have_processes" = x"yes"], [ AC_SUBST(OFPROCESS_M, "OFProcess.m") AC_DEFINE(OF_HAVE_PROCESSES, 1, [Whether we have processes]) Index: src/OFProcess.m ================================================================== --- src/OFProcess.m +++ src/OFProcess.m @@ -27,12 +27,12 @@ # include # include # include #endif -#ifdef __MACH__ -# include +#ifdef HAVE_SPAWN_H +# include #endif #import "OFProcess.h" #import "OFString.h" #import "OFArray.h" @@ -53,12 +53,11 @@ extern char **environ; #endif @interface OFProcess (OF_PRIVATE_CATEGORY) #ifndef _WIN32 -- (void)OF_getArgC: (int*)argc - andArgV: (char***)argv +- (void)OF_getArgV: (char***)argv forProgramName: (OFString*)programName andArguments: (OFArray*)arguments; - (char**)OF_environmentForDictionary: (OFDictionary*)dictionary; #else - (of_char16_t*)OF_environmentForDictionary: (OFDictionary*)dictionary; @@ -139,48 +138,89 @@ @try { #ifndef _WIN32 void *pool = objc_autoreleasePoolPush(); const char *path; - int argc; - char **argv, **env; + char **argv; if (pipe(_readPipe) != 0 || pipe(_writePipe) != 0) @throw [OFInitializationFailedException exceptionWithClass: [self class]]; path = [program cStringWithEncoding: [OFSystemInfo native8BitEncoding]]; - [self OF_getArgC: &argc - andArgV: &argv + [self OF_getArgV: &argv forProgramName: programName andArguments: arguments]; - env = [self OF_environmentForDictionary: environment]; - - if ((_pid = fork()) == 0) { -#ifdef __MACH__ - *_NSGetEnviron() = env; -#else - environ = env; -#endif - - close(_readPipe[0]); - close(_writePipe[1]); - dup2(_writePipe[0], 0); - dup2(_readPipe[1], 1); - execvp(path, argv); - - _exit(EXIT_FAILURE); - } - - close(_readPipe[1]); - close(_writePipe[0]); - [self freeMemory: argv]; - - if (_pid == -1) - @throw [OFInitializationFailedException - exceptionWithClass: [self class]]; + + @try { + char **env = [self + OF_environmentForDictionary: environment]; +# ifdef HAVE_POSIX_SPAWNP + posix_spawn_file_actions_t actions; + posix_spawnattr_t attr; + + if (posix_spawn_file_actions_init(&actions) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + + if (posix_spawnattr_init(&attr) != 0) { + posix_spawn_file_actions_destroy(&actions); + + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + } + + @try { + if (posix_spawn_file_actions_addclose(&actions, + _readPipe[0]) != 0 || + posix_spawn_file_actions_addclose(&actions, + _writePipe[1]) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _writePipe[0], 0) != 0 || + posix_spawn_file_actions_adddup2(&actions, + _readPipe[1], 1) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + +# ifdef POSIX_SPAWN_CLOEXEC_DEFAULT + if (posix_spawnattr_setflags(&attr, + POSIX_SPAWN_CLOEXEC_DEFAULT) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; +# endif + + if (posix_spawnp(&_pid, path, &actions, &attr, + argv, env) != 0) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; + } @finally { + posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); + } +# else + if ((_pid = fork()) == 0) { + environ = env; + + close(_readPipe[0]); + close(_writePipe[1]); + dup2(_writePipe[0], 0); + dup2(_readPipe[1], 1); + execvp(path, argv); + + _exit(EXIT_FAILURE); + } + + if (_pid == -1) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; +# endif + } @finally { + close(_readPipe[1]); + close(_writePipe[0]); + [self freeMemory: argv]; + } objc_autoreleasePoolPop(pool); #else SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; @@ -297,12 +337,11 @@ [super dealloc]; } #ifndef _WIN32 -- (void)OF_getArgC: (int*)argc - andArgV: (char***)argv +- (void)OF_getArgV: (char***)argv forProgramName: (OFString*)programName andArguments: (OFArray*)arguments { OFString *const *objects = [arguments objects]; size_t i, count = [arguments count];