Reimplements Executor and SimpleExecutor start to allow setting stdin/stdout/stderr/cwd

        It may break input/output/communicate, but will ensure child output redirects won't
        break parent process by filling the PIPE.
        Also, catches ProcessExitedWithError and raise FileNotFoundError if exitcode was 127

def start(self):
        """
        Reimplements Executor and SimpleExecutor start to allow setting stdin/stdout/stderr/cwd

        It may break input/output/communicate, but will ensure child output redirects won't
        break parent process by filling the PIPE.
        Also, catches ProcessExitedWithError and raise FileNotFoundError if exitcode was 127
        """
        if self.pre_start_check():
            # Some other executor (or process) is running with same config:
            raise AlreadyRunning(self)

        if self.process is None:
            command = self.command
            if not self._shell:
                command = self.command_parts

            if isinstance(self.stdio, (list, tuple)):
                stdin, stdout, stderr = self.stdio
            else:
                stdin = stdout = stderr = self.stdio
            env = os.environ.copy()
            env[ENV_UUID] = self._uuid
            popen_kwargs = {
                'shell': self._shell,
                'stdin': stdin,
                'stdout': stdout,
                'stderr': stderr,
                'universal_newlines': True,
                'env': env,
                'cwd': self.cwd,
            }
            if platform.system() != 'Windows':
                popen_kwargs['preexec_fn'] = os.setsid
            self.process = subprocess.Popen(
                command,
                **popen_kwargs,
            )

        self._set_timeout()

        try:
            self.wait_for(self.check_subprocess)
        except ProcessExitedWithError as e:
            if e.exit_code == 127:
                raise FileNotFoundError(
                    f'Can not execute {command!r}, check that the executable exists.',
                ) from e
            else:
                output_file_names = {io.name for io in (stdout, stderr) if hasattr(io, 'name')}
                if output_file_names:
                    log.warning('Process output file(s)', output_files=output_file_names)
            raise
        return self