[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
Sun Aug 2 22:03:08 PDT 2009


On Sat, Aug 1, 2009 at 9:51 PM, Daniel Dunbar<daniel at zuster.org> wrote:
> 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?

Scratch that, fixed in r77953.

 - 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