47#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
51#define WIN32_LEAN_AND_MEAN
64 typedef experimental::Subprocess::TArgs TArgs;
65 typedef experimental::Subprocess::TWArgs TWArgs;
67 SubprocessImpl(
const TArgs& args)
69 for (TArgs::const_iterator i = args.begin(); i != args.end(); ++i)
71 wargs_.push_back(util::utf8ToWchar(*i));
75 SubprocessImpl(
const TWArgs& wargs):
82 ::CloseHandle(pi_.hProcess);
83 ::CloseHandle(pi_.hThread);
90 LASS_THROW(
"You need to specify at least one argument: the binary to start.");
93 ZeroMemory(&si_,
sizeof(si_));
95 si_.dwFlags = STARTF_USESHOWWINDOW;
96 si_.wShowWindow = SW_HIDE;
97 ZeroMemory(&pi_,
sizeof(pi_));
99 std::vector<wchar_t> cmd;
100 makeCommandline(cmd);
102 LASS_ENFORCE_WINAPI(::CreateProcessW(wargs_[0].c_str(), &cmd[0], 0, 0, FALSE, 0, 0, 0, &si_, &pi_));
105 void sendSignal(
int )
113 ::TerminateProcess(pi_.hProcess, 0xffffffff);
116 bool checkExitCode(
int& exitCode,
bool join)
const
118 if (join && ::WaitForSingleObject(pi_.hProcess, INFINITE) == WAIT_FAILED)
120 const unsigned err = lass_GetLastError();
121 LASS_THROW(
"Failed to wait for subprocess: (" << err <<
") " << lass_FormatMessage(err));
124 LASS_ENFORCE_WINAPI(::GetExitCodeProcess(pi_.hProcess, &value));
125 if (value == STILL_ACTIVE)
129 exitCode =
static_cast<int>(value);
136 void makeCommandline(std::vector<wchar_t>& cmd)
const
140 for (TWArgs::const_iterator i = wargs_.begin(); i != wargs_.end(); ++i)
142 if (i != wargs_.begin())
146 const std::wstring& arg = *i;
147 const bool mustQuote = arg.empty() || arg.find_first_of(L
" \t") != std::wstring::npos;
152 size_t numBackslashes = 0;
153 for (
size_t k = 0, n = arg.size(); k < n; ++k)
162 numBackslashes = 2 * numBackslashes + 1;
165 cmd.insert(cmd.end(), numBackslashes, L
'\\');
167 cmd.push_back(arg[k]);
170 cmd.insert(cmd.end(), numBackslashes, L
'\\');
173 cmd.insert(cmd.end(), numBackslashes, L
'\\');
181 PROCESS_INFORMATION pi_;
196extern char **environ;
208 typedef experimental::Subprocess::TArgs TArgs;
209 typedef experimental::Subprocess::TWArgs TWArgs;
211 SubprocessImpl(
const TArgs& args):
217 SubprocessImpl(
const TWArgs& wargs):
220 for (TWArgs::const_iterator i = wargs.begin(); i != wargs.end(); ++i)
222 args_.push_back(util::wcharToUtf8(*i));
232 checkExitCode(dummy,
false);
242 LASS_THROW(
"You need to specify at least one argument: the binary to start.");
245 const size_t argc = args_.size();
246 ScopedArgv argv(argc);
247 for (
size_t k = 0; k < argc; ++k)
249 argv[k] = ::strdup(args_[k].c_str());
252 LASS_ENFORCE_CLIB_RC(posix_spawnp(&pid_, argv[0], 0, 0, argv.ptr(), environ));
255 void sendSignal(
int signal)
259 ::kill(pid_, signal);
268 bool checkExitCode(
int& exitCode,
bool join)
271 const int options = join ? 0 : WNOHANG;
278 const pid_t pid = LASS_ENFORCE_CLIB(waitpid(pid_, &status, options));
283 LASS_ASSERT(pid == pid_);
285 if (WIFSIGNALED(status))
287 exitCode = -(WTERMSIG(status));
291 else if (WIFEXITED(status))
293 exitCode = WEXITSTATUS(status);
299 LASS_THROW(
"Internal error");
308 ScopedArgv(
size_t argc)
310 argv_.resize(argc + 1, 0);
314 for (TArgv::reverse_iterator i = argv_.rbegin(), end = argv_.rend(); i != end; ++i)
319 char*& operator[](
size_t index)
328 typedef std::vector<char*> TArgv;
348namespace experimental
351Subprocess::Subprocess(
const TArgs& args) :
352 pimpl_(new impl::SubprocessImpl(args)),
361Subprocess::Subprocess(
const TWArgs& args) :
362 pimpl_(new impl::SubprocessImpl(args)),
371Subprocess::~Subprocess()
380 catch (
const std::exception& error)
382 std::cerr <<
"[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: " << error.what() << std::endl;
388void Subprocess::run()
392 LASS_THROW(
"Subprocess cannot be run more than once.");
399int Subprocess::join()
402 if (!checkExitCode(
true))
404 LASS_THROW(
"Failed to join subprocess.");
406 LASS_ASSERT(hasExitCode_);
411void Subprocess::detach()
417void Subprocess::sendSignal(
int signal)
419 pimpl_->sendSignal(signal);
423void Subprocess::kill()
425 if (!isStarted_ || !isRunning())
429 enforceNotDetached();
434bool Subprocess::isRunning()
const
436 return isStarted_ && !checkExitCode();
440bool Subprocess::isDetached()
const
446int Subprocess::exitCode()
const
449 if (!checkExitCode())
451 LASS_THROW(
"Subprocess is still running.");
453 LASS_ASSERT(hasExitCode_);
458void Subprocess::enforceStarted()
const
462 LASS_THROW(
"Subprocess has not started yet.");
467void Subprocess::enforceNotDetached()
const
471 LASS_THROW(
"Subprocess is detached.");
476bool Subprocess::checkExitCode(
bool join)
const
482 enforceNotDetached();
483 if (pimpl_->checkExitCode(exitCode_, join))
general utility, debug facilities, ...
Library for Assembled Shared Sources.