def run(self, timeout=-1):
        """
        Run the subprocess.

        Arguments:
            timeout (optional) If a positive real value, then timout after
                the given number of seconds.

        Raises:
            SubprocessError If subprocess has not completed after "timeout"
                seconds.
        """
        def target():
            self.process = subprocess.Popen(self.cmd,
                                            stdout=self.stdout_dest,
                                            stderr=self.stderr_dest,
                                            shell=self.shell)
            stdout, stderr = self.process.communicate()

            # Decode output if the user wants, and if there is any.
            if self.decode_out:
                if stdout:
                    self.stdout = stdout.decode("utf-8")
                if stderr:
                    self.stderr = stderr.decode("utf-8")

        thread = threading.Thread(target=target)
        thread.start()

        if timeout > 0:
            thread.join(timeout)
            if thread.is_alive():
                self.process.terminate()
                thread.join()
                raise SubprocessError(("Reached timeout after {t} seconds"
                                       .format(t=timeout)))
        else:
            thread.join()

        return self.process.returncode, self.stdout, self.stderr
Run the subprocess.

        Arguments:
            timeout (optional) If a positive real value, then timout after
                the given number of seconds.

        Raises:
            SubprocessError If subprocess has not completed after "timeout"
                seconds.