[llvm-commits] [llvm] r76340 - in /llvm/trunk: include/llvm/System/Program.h lib/System/Program.cpp lib/System/Unix/Program.inc lib/System/Win32/Program.inc

Daniel Dunbar daniel at zuster.org
Sat Aug 1 21:51:26 PDT 2009


Hi Mikhail,

Unfortunately I'm not seeing this until now, but this refactoring has
one key flaw. On Windows, it introduces a race condition between where
the program releases the process handle, and where it gets the handle
again in Program::Wait. I believe that the program needs to hold on to
the handle for as long as clients may want information about it.

This causes substantial problems for the clang driver on Windows. Do
you think you can work out an alternate solution that avoids this
problem?

 - Daniel

On Sat, Jul 18, 2009 at 2:43 PM, Mikhail Glushenkov<foldr at codedgers.com> wrote:
> Author: foldr
> Date: Sat Jul 18 16:43:12 2009
> New Revision: 76340
>
> URL: http://llvm.org/viewvc/llvm-project?rev=76340&view=rev
> Log:
> Remove duplication in Program::Execute{And,No}Wait.
>
> Implemented by moving the code out of static functions into methods of Program
> class.
>
> Modified:
>    llvm/trunk/include/llvm/System/Program.h
>    llvm/trunk/lib/System/Program.cpp
>    llvm/trunk/lib/System/Unix/Program.inc
>    llvm/trunk/lib/System/Win32/Program.inc
>
> Modified: llvm/trunk/include/llvm/System/Program.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/System/Program.h?rev=76340&r1=76339&r2=76340&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/System/Program.h (original)
> +++ llvm/trunk/include/llvm/System/Program.h Sat Jul 18 16:43:12 2009
> @@ -19,6 +19,9 @@
>  namespace llvm {
>  namespace sys {
>
> +  // TODO: Add operations to communicate with the process, redirect its I/O,
> +  // etc.
> +
>   /// This class provides an abstraction for programs that are executable by the
>   /// operating system. It provides a platform generic way to find executable
>   /// programs from the path and to execute them in various ways. The sys::Path
> @@ -26,104 +29,112 @@
>   /// @since 1.4
>   /// @brief An abstraction for finding and executing programs.
>   class Program {
> +    unsigned Pid_;
> +
> +    // Noncopyable.
> +    Program(const Program& other);
> +    Program& operator=(const Program& other);
> +
>     /// @name Methods
>     /// @{
> -    public:
> -      /// This static constructor (factory) will attempt to locate a program in
> -      /// the operating system's file system using some pre-determined set of
> -      /// locations to search (e.g. the PATH on Unix).
> -      /// @returns A Path object initialized to the path of the program or a
> -      /// Path object that is empty (invalid) if the program could not be found.
> -      /// @throws nothing
> -      /// @brief Construct a Program by finding it by name.
> -      static Path FindProgramByName(const std::string& name);
> -
> -      /// This function executes the program using the \p arguments provided and
> -      /// waits for the program to exit. This function will block the current
> -      /// program until the invoked program exits. The invoked program will
> -      /// inherit the stdin, stdout, and stderr file descriptors, the
> -      /// environment and other configuration settings of the invoking program.
> -      /// If Path::executable() does not return true when this function is
> -      /// called then a std::string is thrown.
> -      /// @returns an integer result code indicating the status of the program.
> -      /// A zero or positive value indicates the result code of the program. A
> -      /// negative value is the signal number on which it terminated.
> -      /// @see FindProgrambyName
> -      /// @brief Executes the program with the given set of \p args.
> -      static int ExecuteAndWait(
> -        const Path& path,  ///< sys::Path object providing the path of the
> -          ///< program to be executed. It is presumed this is the result of
> -          ///< the FindProgramByName method.
> -        const char** args, ///< A vector of strings that are passed to the
> -          ///< program.  The first element should be the name of the program.
> -          ///< The list *must* be terminated by a null char* entry.
> -        const char ** env = 0, ///< An optional vector of strings to use for
> -          ///< the program's environment. If not provided, the current program's
> -          ///< environment will be used.
> -        const sys::Path** redirects = 0, ///< An optional array of pointers to
> -          ///< Paths. If the array is null, no redirection is done. The array
> -          ///< should have a size of at least three. If the pointer in the array
> -          ///< are not null, then the inferior process's stdin(0), stdout(1),
> -          ///< and stderr(2) will be redirected to the corresponding Paths.
> -          ///< When an empty Path is passed in, the corresponding file
> -          ///< descriptor will be disconnected (ie, /dev/null'd) in a portable
> -          ///< way.
> -        unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount
> -          ///< of time to wait for the child process to exit. If the time
> -          ///< expires, the child is killed and this call returns. If zero,
> -          ///< this function will wait until the child finishes or forever if
> -          ///< it doesn't.
> -        unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
> -          ///< of memory can be allocated by process. If memory usage will be
> -          ///< higher limit, the child is killed and this call returns. If zero
> -          ///< - no memory limit.
> -        std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
> -          ///< instance in which error messages will be returned. If the string
> -          ///< is non-empty upon return an error occurred while invoking the
> -          ///< program.
> +  public:
> +
> +    Program() : Pid_(0)
> +    {}
> +
> +    /// This function executes the program using the \p arguments provided.  The
> +    /// invoked program will inherit the stdin, stdout, and stderr file
> +    /// descriptors, the environment and other configuration settings of the
> +    /// invoking program. If Path::executable() does not return true when this
> +    /// function is called then a std::string is thrown.
> +    /// @returns false in case of error, true otherwise.
> +    /// @see FindProgramByName
> +    /// @brief Executes the program with the given set of \p args.
> +    bool Execute
> +    ( const Path& path,  ///< sys::Path object providing the path of the
> +      ///< program to be executed. It is presumed this is the result of
> +      ///< the FindProgramByName method.
> +      const char** args, ///< A vector of strings that are passed to the
> +      ///< program.  The first element should be the name of the program.
> +      ///< The list *must* be terminated by a null char* entry.
> +      const char ** env = 0, ///< An optional vector of strings to use for
> +      ///< the program's environment. If not provided, the current program's
> +      ///< environment will be used.
> +      const sys::Path** redirects = 0, ///< An optional array of pointers to
> +      ///< Paths. If the array is null, no redirection is done. The array
> +      ///< should have a size of at least three. If the pointer in the array
> +      ///< are not null, then the inferior process's stdin(0), stdout(1),
> +      ///< and stderr(2) will be redirected to the corresponding Paths.
> +      ///< When an empty Path is passed in, the corresponding file
> +      ///< descriptor will be disconnected (ie, /dev/null'd) in a portable
> +      ///< way.
> +      unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
> +      ///< of memory can be allocated by process. If memory usage will be
> +      ///< higher limit, the child is killed and this call returns. If zero
> +      ///< - no memory limit.
> +      std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
> +      ///< instance in which error messages will be returned. If the string
> +      ///< is non-empty upon return an error occurred while invoking the
> +      ///< program.
> +      );
> +
> +    /// This function waits for the program to exit. This function will block
> +    /// the current program until the invoked program exits.
> +    /// @returns an integer result code indicating the status of the program.
> +    /// A zero or positive value indicates the result code of the program. A
> +    /// negative value is the signal number on which it terminated.
> +    /// @see Execute
> +    /// @brief Waits for the program to exit.
> +    int Wait
> +    ( unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount
> +      ///< of time to wait for the child process to exit. If the time
> +      ///< expires, the child is killed and this call returns. If zero,
> +      ///< this function will wait until the child finishes or forever if
> +      ///< it doesn't.
> +      std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
> +      ///< instance in which error messages will be returned. If the string
> +      ///< is non-empty upon return an error occurred while invoking the
> +      ///< program.
>       );
> -      // These methods change the specified standard stream (stdin or stdout) to
> -      // binary mode. They return true if an error occurred
> -      static bool ChangeStdinToBinary();
> -      static bool ChangeStdoutToBinary();
> +
> +    /// This static constructor (factory) will attempt to locate a program in
> +    /// the operating system's file system using some pre-determined set of
> +    /// locations to search (e.g. the PATH on Unix).
> +    /// @returns A Path object initialized to the path of the program or a
> +    /// Path object that is empty (invalid) if the program could not be found.
> +    /// @throws nothing
> +    /// @brief Construct a Program by finding it by name.
> +    static Path FindProgramByName(const std::string& name);
> +
> +    // These methods change the specified standard stream (stdin or stdout) to
> +    // binary mode. They return true if an error occurred
> +    static bool ChangeStdinToBinary();
> +    static bool ChangeStdoutToBinary();
> +
> +    /// A convenience function equivalent to Program prg; prg.Execute(..);
> +    /// prg.Wait(..);
> +    /// @throws nothing
> +    /// @see Execute, Wait
> +    static int ExecuteAndWait(const Path& path,
> +                              const char** args,
> +                              const char ** env = 0,
> +                              const sys::Path** redirects = 0,
> +                              unsigned secondsToWait = 0,
> +                              unsigned memoryLimit = 0,
> +                              std::string* ErrMsg = 0);
> +
> +    /// A convenience function equivalent to Program prg; prg.Execute(..);
> +    /// @throws nothing
> +    /// @see Execute
> +    static void ExecuteNoWait(const Path& path,
> +                              const char** args,
> +                              const char ** env = 0,
> +                              const sys::Path** redirects = 0,
> +                              unsigned memoryLimit = 0,
> +                              std::string* ErrMsg = 0);
> +
>     /// @}
>
> -     /// This function executes the program using the \p arguments provided and
> -     /// waits for the program to exit. This function will block the current
> -     /// program until the invoked program exits. The invoked program will
> -     /// inherit the stdin, stdout, and stderr file descriptors, the
> -     /// environment and other configuration settings of the invoking program.
> -     /// If Path::executable() does not return true when this function is
> -     /// called then a std::string is thrown.
> -     /// @returns an integer result code indicating the status of the program.
> -     /// A zero or positive value indicates the result code of the program. A
> -     /// negative value is the signal number on which it terminated.
> -     /// @see FindProgrambyName
> -     /// @brief Executes the program with the given set of \p args.
> -     static void ExecuteNoWait(
> -        const Path& path,  ///< sys::Path object providing the path of the
> -        ///< program to be executed. It is presumed this is the result of
> -        ///< the FindProgramByName method.
> -        const char** args, ///< A vector of strings that are passed to the
> -        ///< program.  The first element should be the name of the program.
> -        ///< The list *must* be terminated by a null char* entry.
> -        const char ** env = 0, ///< An optional vector of strings to use for
> -        ///< the program's environment. If not provided, the current program's
> -        ///< environment will be used.
> -        const sys::Path** redirects = 0, ///< An optional array of pointers to
> -        ///< Paths. If the array is null, no redirection is done. The array
> -        ///< should have a size of at least three. If the pointer in the array
> -        ///< are not null, then the inferior process's stdin(0), stdout(1),
> -        ///< and stderr(2) will be redirected to the corresponding Paths.
> -        unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount
> -        ///< of memory can be allocated by process. If memory usage will be
> -        ///< higher limit, the child is killed and this call returns. If zero -
> -        ///< no memory limit.
> -        std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string
> -        ///< instance in which error messages will be returned. If the string
> -        ///< is non-empty upon return an error occurred while invoking the
> -        ///< program.
> -        );
>   };
>  }
>  }
>
> Modified: llvm/trunk/lib/System/Program.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Program.cpp?rev=76340&r1=76339&r2=76340&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/System/Program.cpp (original)
> +++ llvm/trunk/lib/System/Program.cpp Sat Jul 18 16:43:12 2009
> @@ -22,6 +22,33 @@
>  //===          independent code.
>  //===----------------------------------------------------------------------===//
>
> +int
> +Program::ExecuteAndWait(const Path& path,
> +                        const char** args,
> +                        const char** envp,
> +                        const Path** redirects,
> +                        unsigned secondsToWait,
> +                        unsigned memoryLimit,
> +                        std::string* ErrMsg) {
> +  Program prg;
> +  if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg))
> +    return prg.Wait(secondsToWait, ErrMsg);
> +  else
> +    return -1;
> +}
> +
> +void
> +Program::ExecuteNoWait(const Path& path,
> +                       const char** args,
> +                       const char** envp,
> +                       const Path** redirects,
> +                       unsigned memoryLimit,
> +                       std::string* ErrMsg) {
> +  Program prg;
> +  prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg);
> +}
> +
> +
>  }
>
>  // Include the platform-specific parts of this class.
>
> Modified: llvm/trunk/lib/System/Unix/Program.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Unix/Program.inc?rev=76340&r1=76339&r2=76340&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/System/Unix/Program.inc (original)
> +++ llvm/trunk/lib/System/Unix/Program.inc Sat Jul 18 16:43:12 2009
> @@ -142,49 +142,47 @@
>  #endif
>  }
>
> -int
> -Program::ExecuteAndWait(const Path& path,
> -                        const char** args,
> -                        const char** envp,
> -                        const Path** redirects,
> -                        unsigned secondsToWait,
> -                        unsigned memoryLimit,
> -                        std::string* ErrMsg)
> +bool
> +Program::Execute(const Path& path,
> +                 const char** args,
> +                 const char** envp,
> +                 const Path** redirects,
> +                 unsigned memoryLimit,
> +                 std::string* ErrMsg)
>  {
>   if (!path.canExecute()) {
>     if (ErrMsg)
>       *ErrMsg = path.toString() + " is not executable";
> -    return -1;
> +    return false;
>   }
>
> -#ifdef HAVE_SYS_WAIT_H
>   // Create a child process.
>   int child = fork();
>   switch (child) {
>     // An error occured:  Return to the caller.
>     case -1:
>       MakeErrMsg(ErrMsg, "Couldn't fork");
> -      return -1;
> +      return false;
>
>     // Child process: Execute the program.
>     case 0: {
>       // Redirect file descriptors...
>       if (redirects) {
>         // Redirect stdin
> -        if (RedirectIO(redirects[0], 0, ErrMsg)) { return -1; }
> +        if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; }
>         // Redirect stdout
> -        if (RedirectIO(redirects[1], 1, ErrMsg)) { return -1; }
> +        if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; }
>         if (redirects[1] && redirects[2] &&
>             *(redirects[1]) == *(redirects[2])) {
>           // If stdout and stderr should go to the same place, redirect stderr
>           // to the FD already open for stdout.
>           if (-1 == dup2(1,2)) {
>             MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
> -            return -1;
> +            return false;
>           }
>         } else {
>           // Just redirect stderr
> -          if (RedirectIO(redirects[2], 2, ErrMsg)) { return -1; }
> +          if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; }
>         }
>       }
>
> @@ -214,8 +212,23 @@
>   fsync(1);
>   fsync(2);
>
> +  Pid_ = child;
> +
> +  return true;
> +}
> +
> +int
> +Program::Wait(unsigned secondsToWait,
> +              std::string* ErrMsg)
> +{
> +#ifdef HAVE_SYS_WAIT_H
>   struct sigaction Act, Old;
>
> +  if (Pid_ == 0) {
> +    MakeErrMsg(ErrMsg, "Process not started!");
> +    return -1;
> +  }
> +
>   // Install a timeout handler.
>   if (secondsToWait) {
>     Timeout = false;
> @@ -229,6 +242,7 @@
>
>   // Parent process: Wait for the child process to terminate.
>   int status;
> +  int child = this->Pid_;
>   while (wait(&status) != child)
>     if (secondsToWait && errno == EINTR) {
>       // Kill the child.
> @@ -274,78 +288,6 @@
>
>  }
>
> -void
> -Program::ExecuteNoWait(const Path& path,
> -                       const char** args,
> -                       const char** envp,
> -                       const Path** redirects,
> -                       unsigned memoryLimit,
> -                       std::string* ErrMsg)
> -{
> -  if (!path.canExecute()) {
> -    if (ErrMsg)
> -      *ErrMsg = path.toString() + " is not executable";
> -    return;
> -  }
> -
> -  // Create a child process.
> -  int child = fork();
> -  switch (child) {
> -    // An error occured:  Return to the caller.
> -    case -1:
> -      MakeErrMsg(ErrMsg, "Couldn't fork");
> -      return;
> -
> -    // Child process: Execute the program.
> -    case 0: {
> -      // Redirect file descriptors...
> -      if (redirects) {
> -        // Redirect stdin
> -        if (RedirectIO(redirects[0], 0, ErrMsg)) { return; }
> -        // Redirect stdout
> -        if (RedirectIO(redirects[1], 1, ErrMsg)) { return; }
> -        if (redirects[1] && redirects[2] &&
> -            *(redirects[1]) == *(redirects[2])) {
> -          // If stdout and stderr should go to the same place, redirect stderr
> -          // to the FD already open for stdout.
> -          if (-1 == dup2(1,2)) {
> -            MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout");
> -            return;
> -          }
> -        } else {
> -          // Just redirect stderr
> -          if (RedirectIO(redirects[2], 2, ErrMsg)) { return; }
> -        }
> -      }
> -
> -      // Set memory limits
> -      if (memoryLimit!=0) {
> -        SetMemoryLimits(memoryLimit);
> -      }
> -
> -      // Execute!
> -      if (envp != 0)
> -        execve (path.c_str(), (char**)args, (char**)envp);
> -      else
> -        execv (path.c_str(), (char**)args);
> -      // If the execve() failed, we should exit and let the parent pick up
> -      // our non-zero exit status.
> -      exit (errno);
> -    }
> -
> -    // Parent process: Break out of the switch to do our processing.
> -    default:
> -      break;
> -  }
> -
> -  // Make sure stderr and stdout have been flushed
> -  std::cerr << std::flush;
> -  std::cout << std::flush;
> -  fsync(1);
> -  fsync(2);
> -
> -}
> -
>  bool Program::ChangeStdinToBinary(){
>   // Do nothing, as Unix doesn't differentiate between text and binary.
>   return false;
>
> Modified: llvm/trunk/lib/System/Win32/Program.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Win32/Program.inc?rev=76340&r1=76339&r2=76340&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/System/Win32/Program.inc (original)
> +++ llvm/trunk/lib/System/Win32/Program.inc Sat Jul 18 16:43:12 2009
> @@ -109,18 +109,17 @@
>                                       DWORD cbJobObjectInfoLength);
>  #endif
>
> -int
> -Program::ExecuteAndWait(const Path& path,
> -                        const char** args,
> -                        const char** envp,
> -                        const Path** redirects,
> -                        unsigned secondsToWait,
> -                        unsigned memoryLimit,
> -                        std::string* ErrMsg) {
> +bool
> +Program::Execute(const Path& path,
> +                 const char** args,
> +                 const char** envp,
> +                 const Path** redirects,
> +                 unsigned memoryLimit,
> +                 std::string* ErrMsg) {
>   if (!path.canExecute()) {
>     if (ErrMsg)
>       *ErrMsg = "program not executable";
> -    return -1;
> +    return false;
>   }
>
>   // Windows wants a command line, not an array of args, to pass to the new
> @@ -195,13 +194,13 @@
>     si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
>     if (si.hStdInput == INVALID_HANDLE_VALUE) {
>       MakeErrMsg(ErrMsg, "can't redirect stdin");
> -      return -1;
> +      return false;
>     }
>     si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
>     if (si.hStdOutput == INVALID_HANDLE_VALUE) {
>       CloseHandle(si.hStdInput);
>       MakeErrMsg(ErrMsg, "can't redirect stdout");
> -      return -1;
> +      return false;
>     }
>     if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
>       // If stdout and stderr should go to the same place, redirect stderr
> @@ -216,7 +215,7 @@
>         CloseHandle(si.hStdInput);
>         CloseHandle(si.hStdOutput);
>         MakeErrMsg(ErrMsg, "can't redirect stderr");
> -        return -1;
> +        return false;
>       }
>     }
>   }
> @@ -242,8 +241,9 @@
>     SetLastError(err);
>     MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
>                path.toString() + "'");
> -    return -1;
> +    return false;
>   }
> +  Pid_ = pi.dwProcessId;
>
>   // Make sure these get closed no matter what.
>   AutoHandle hProcess(pi.hProcess);
> @@ -270,204 +270,50 @@
>       MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
>       TerminateProcess(pi.hProcess, 1);
>       WaitForSingleObject(pi.hProcess, INFINITE);
> -      return -1;
> +      return false;
>     }
>   }
>
> -  // Wait for it to terminate.
> +  return true;
> +}
> +
> +int
> +Program::Wait(unsigned secondsToWait,
> +              std::string* ErrMsg) {
> +  if (Pid_ == 0) {
> +    MakeErrMsg(ErrMsg, "Process not started!");
> +    return -1;
> +  }
> +
> +  AutoHandle hProcess = OpenProcess(SYNCHRONIZE, FALSE, Pid_);
> +
> +  // Wait for the process to terminate.
>   DWORD millisecondsToWait = INFINITE;
>   if (secondsToWait > 0)
>     millisecondsToWait = secondsToWait * 1000;
>
> -  if (WaitForSingleObject(pi.hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
> -    if (!TerminateProcess(pi.hProcess, 1)) {
> -      MakeErrMsg(ErrMsg, std::string("Failed to terminate timed-out program '")
> -          + path.toString() + "'");
> +  if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) {
> +    if (!TerminateProcess(hProcess, 1)) {
> +      MakeErrMsg(ErrMsg, "Failed to terminate timed-out program.");
>       return -1;
>     }
> -    WaitForSingleObject(pi.hProcess, INFINITE);
> +    WaitForSingleObject(hProcess, INFINITE);
>   }
>
>   // Get its exit status.
>   DWORD status;
> -  rc = GetExitCodeProcess(pi.hProcess, &status);
> -  err = GetLastError();
> +  BOOL rc = GetExitCodeProcess(hProcess, &status);
> +  DWORD err = GetLastError();
>
>   if (!rc) {
>     SetLastError(err);
> -    MakeErrMsg(ErrMsg, std::string("Failed getting status for program '") +
> -               path.toString() + "'");
> +    MakeErrMsg(ErrMsg, "Failed getting status for program.");
>     return -1;
>   }
>
>   return status;
>  }
>
> -void
> -Program::ExecuteNoWait(const Path& path,
> -                       const char** args,
> -                       const char** envp,
> -                       const Path** redirects,
> -                       unsigned memoryLimit,
> -                       std::string* ErrMsg) {
> -  if (!path.canExecute()) {
> -    if (ErrMsg)
> -      *ErrMsg = "program not executable";
> -    return;
> -  }
> -
> -  // Windows wants a command line, not an array of args, to pass to the new
> -  // process.  We have to concatenate them all, while quoting the args that
> -  // have embedded spaces.
> -
> -  // First, determine the length of the command line.
> -  unsigned len = 0;
> -  for (unsigned i = 0; args[i]; i++) {
> -    len += strlen(args[i]) + 1;
> -    if (strchr(args[i], ' '))
> -      len += 2;
> -  }
> -
> -  // Now build the command line.
> -  char *command = reinterpret_cast<char *>(_alloca(len+1));
> -  char *p = command;
> -
> -  for (unsigned i = 0; args[i]; i++) {
> -    const char *arg = args[i];
> -    size_t len = strlen(arg);
> -    bool needsQuoting = strchr(arg, ' ') != 0;
> -    if (needsQuoting)
> -      *p++ = '"';
> -    memcpy(p, arg, len);
> -    p += len;
> -    if (needsQuoting)
> -      *p++ = '"';
> -    *p++ = ' ';
> -  }
> -
> -  *p = 0;
> -
> -  // The pointer to the environment block for the new process.
> -  char *envblock = 0;
> -
> -  if (envp) {
> -    // An environment block consists of a null-terminated block of
> -    // null-terminated strings. Convert the array of environment variables to
> -    // an environment block by concatenating them.
> -
> -    // First, determine the length of the environment block.
> -    len = 0;
> -    for (unsigned i = 0; envp[i]; i++)
> -      len += strlen(envp[i]) + 1;
> -
> -    // Now build the environment block.
> -    envblock = reinterpret_cast<char *>(_alloca(len+1));
> -    p = envblock;
> -
> -    for (unsigned i = 0; envp[i]; i++) {
> -      const char *ev = envp[i];
> -      size_t len = strlen(ev) + 1;
> -      memcpy(p, ev, len);
> -      p += len;
> -    }
> -
> -    *p = 0;
> -  }
> -
> -  // Create a child process.
> -  STARTUPINFO si;
> -  memset(&si, 0, sizeof(si));
> -  si.cb = sizeof(si);
> -  si.hStdInput = INVALID_HANDLE_VALUE;
> -  si.hStdOutput = INVALID_HANDLE_VALUE;
> -  si.hStdError = INVALID_HANDLE_VALUE;
> -
> -  if (redirects) {
> -    si.dwFlags = STARTF_USESTDHANDLES;
> -
> -    si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg);
> -    if (si.hStdInput == INVALID_HANDLE_VALUE) {
> -      MakeErrMsg(ErrMsg, "can't redirect stdin");
> -      return;
> -    }
> -    si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg);
> -    if (si.hStdOutput == INVALID_HANDLE_VALUE) {
> -      CloseHandle(si.hStdInput);
> -      MakeErrMsg(ErrMsg, "can't redirect stdout");
> -      return;
> -    }
> -    if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) {
> -      // If stdout and stderr should go to the same place, redirect stderr
> -      // to the handle already open for stdout.
> -      DuplicateHandle(GetCurrentProcess(), si.hStdOutput,
> -                      GetCurrentProcess(), &si.hStdError,
> -                      0, TRUE, DUPLICATE_SAME_ACCESS);
> -    } else {
> -      // Just redirect stderr
> -      si.hStdError = RedirectIO(redirects[2], 2, ErrMsg);
> -      if (si.hStdError == INVALID_HANDLE_VALUE) {
> -        CloseHandle(si.hStdInput);
> -        CloseHandle(si.hStdOutput);
> -        MakeErrMsg(ErrMsg, "can't redirect stderr");
> -        return;
> -      }
> -    }
> -  }
> -
> -  PROCESS_INFORMATION pi;
> -  memset(&pi, 0, sizeof(pi));
> -
> -  fflush(stdout);
> -  fflush(stderr);
> -  BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0,
> -                          envblock, NULL, &si, &pi);
> -  DWORD err = GetLastError();
> -
> -  // Regardless of whether the process got created or not, we are done with
> -  // the handles we created for it to inherit.
> -  CloseHandle(si.hStdInput);
> -  CloseHandle(si.hStdOutput);
> -  CloseHandle(si.hStdError);
> -
> -  // Now return an error if the process didn't get created.
> -  if (!rc)
> -  {
> -    SetLastError(err);
> -    MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") +
> -               path.toString() + "'");
> -    return;
> -  }
> -
> -  // Make sure these get closed no matter what.
> -  AutoHandle hProcess(pi.hProcess);
> -  AutoHandle hThread(pi.hThread);
> -
> -  // Assign the process to a job if a memory limit is defined.
> -  AutoHandle hJob(0);
> -  if (memoryLimit != 0) {
> -    hJob = CreateJobObject(0, 0);
> -    bool success = false;
> -    if (hJob != 0) {
> -      JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
> -      memset(&jeli, 0, sizeof(jeli));
> -      jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY;
> -      jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576;
> -      if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation,
> -                                  &jeli, sizeof(jeli))) {
> -        if (AssignProcessToJobObject(hJob, pi.hProcess))
> -          success = true;
> -      }
> -    }
> -    if (!success) {
> -      SetLastError(GetLastError());
> -      MakeErrMsg(ErrMsg, std::string("Unable to set memory limit"));
> -      TerminateProcess(pi.hProcess, 1);
> -      WaitForSingleObject(pi.hProcess, INFINITE);
> -      return;
> -    }
> -  }
> -}
> -
>  bool Program::ChangeStdinToBinary(){
>   int result = _setmode( _fileno(stdin), _O_BINARY );
>   return result == -1;
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>




More information about the llvm-commits mailing list