implement subprocess detach and validity checks

master
Daniel Kolesa 2017-05-13 00:00:44 +02:00
parent 5bbee30f6c
commit 06687881c1
2 changed files with 41 additions and 12 deletions

View File

@ -284,7 +284,7 @@ struct OSTD_EXPORT subprocess {
*
* @throws ostd::subprocess_error on failure of any kind.
*
* @see open_path(), open_command()
* @see open_path(), open_command(), valid()
*/
int close();
@ -297,11 +297,13 @@ struct OSTD_EXPORT subprocess {
*
* If `path` is empty, the first element of `args` is used.
*
* If this fails, ostd::subprocess_error will be thrown.
* If this fails for any reason, ostd::subprocess_error will be thrown.
* Having another child process running is considered a failure, so
* use close() or detach() before opening another.
*
* On success, a new subprocess will be created and this will return
* without waiting for it to finish. Use close() to wait and get the
* return code.
* return code or detach() to give up ownership of the child process.
*
* @throws ostd::subprocess_error on failure of any kind.
*
@ -329,11 +331,13 @@ struct OSTD_EXPORT subprocess {
*
* If `cmd` is empty, the first element of `args` is used.
*
* If this fails, ostd::subprocess_error will be thrown.
* If this fails for any reason, ostd::subprocess_error will be thrown.
* Having another child process running is considered a failure, so
* use close() or detach() before opening another.
*
* On success, a new subprocess will be created and this will return
* without waiting for it to finish. Use close() to wait and get the
* return code.
* return code or detach() to give up ownership of the child process.
*
* @throws ostd::subprocess_error on failure of any kind.
*
@ -350,6 +354,31 @@ struct OSTD_EXPORT subprocess {
open_command(nullptr, std::forward<InputRange>(args));
}
/** @brief Detaches the child process.
*
* If there is a running child process, makes it so that it's no
* longer owned by this subprocess object. The child process will
* keep running even after the subprocess object has died.
*
* @throws ostd::subprocess_error if there is no child process.
*
* @see valid()
*/
void detach() {
if (!p_current) {
throw subprocess_error{"no child process"};
}
reset();
}
/** @brief Checks if there is a running child process.
*
* @returns If there is one, true, otherwise false.
*/
bool valid() const noexcept {
return !!p_current;
}
private:
template<typename InputRange>
void open_full(string_range cmd, InputRange args, bool use_path) {
@ -357,6 +386,11 @@ private:
std::is_constructible_v<std::string, range_reference_t<InputRange>>,
"The arguments must be strings"
);
if (p_current) {
throw subprocess_error{"another child process already running"};
}
std::vector<std::string> argv;
for (; !args.empty(); args.pop_front()) {
argv.emplace_back(args.front());

View File

@ -390,32 +390,27 @@ OSTD_EXPORT void subprocess::open_impl(
}
OSTD_EXPORT void subprocess::reset() {
p_current = nullptr;
CloseHandle(static_cast<HANDLE>(std::exchange(p_current, nullptr)));
}
OSTD_EXPORT int subprocess::close() {
if (!p_current) {
throw subprocess_error{"no child process"};
}
HANDLE *proc = static_cast<HANDLE *>(p_current);
HANDLE proc = static_cast<HANDLE>(p_current);
if (WaitForSingleObject(proc, INFINITE) == WAIT_FAILED) {
CloseHandle(proc);
reset();
throw subprocess_error{"child process wait failed"};
}
DWORD ec = 0;
if (!GetExitCodeProcess(proc, &ec)) {
CloseHandle(proc);
reset();
throw subprocess_error{"could not retrieve exit code"};
}
CloseHandle(proc);
reset();
return int(ec);
}