hide platform-specific data from subprocess

master
Daniel Kolesa 2017-05-08 20:32:36 +02:00
parent 31c3602839
commit ea7f4062b7
2 changed files with 57 additions and 25 deletions

View File

@ -103,11 +103,9 @@ struct OSTD_EXPORT subprocess {
subprocess(subprocess &&i): subprocess(subprocess &&i):
use_in(i.use_in), use_out(i.use_out), use_err(i.use_err), use_in(i.use_in), use_out(i.use_out), use_err(i.use_err),
in(std::move(i.in)), out(std::move(i.out)), err(std::move(i.err)), in(std::move(i.in)), out(std::move(i.out)), err(std::move(i.err))
pid(i.pid), errno_fd(i.errno_fd)
{ {
i.pid = -1; move_data(i);
i.errno_fd = -1;
} }
subprocess &operator=(subprocess &&i) { subprocess &operator=(subprocess &&i) {
@ -123,8 +121,7 @@ struct OSTD_EXPORT subprocess {
swap(in, i.in); swap(in, i.in);
swap(out, i.out); swap(out, i.out);
swap(err, i.err); swap(err, i.err);
swap(pid, i.pid); swap_data(i);
swap(errno_fd, i.errno_fd);
} }
~subprocess(); ~subprocess();
@ -177,8 +174,11 @@ private:
); );
void reset(); void reset();
void move_data(subprocess &i);
void swap_data(subprocess &i);
int pid = -1, errno_fd = -1; std::aligned_storage_t<2 * sizeof(void *)> p_data;
void *p_current = nullptr;
}; };
/** @} */ /** @} */

View File

@ -128,6 +128,10 @@ OSTD_EXPORT void split_args_impl(
} /* namespace detail */ } /* namespace detail */
#ifndef OSTD_PLATFORM_WIN32 #ifndef OSTD_PLATFORM_WIN32
struct data {
int pid = -1, errno_fd = -1;
};
struct pipe { struct pipe {
int fd[2] = { -1, -1 }; int fd[2] = { -1, -1 };
@ -197,6 +201,9 @@ OSTD_EXPORT void subprocess::open_impl(
} }
argp[args.size()] = nullptr; argp[args.size()] = nullptr;
p_current = ::new (reinterpret_cast<void *>(&p_data)) data{};
data *pd = static_cast<data *>(p_current);
/* fd_errno used to detect if exec failed */ /* fd_errno used to detect if exec failed */
pipe fd_errno, fd_stdin, fd_stdout, fd_stderr; pipe fd_errno, fd_stdin, fd_stdout, fd_stderr;
@ -263,31 +270,56 @@ OSTD_EXPORT void subprocess::open_impl(
fd_stderr.close(true); fd_stderr.close(true);
fd_stderr.fdopen(err, false); fd_stderr.fdopen(err, false);
} }
pid = int(cpid); pd->pid = int(cpid);
errno_fd = std::exchange(fd_errno[1], -1); pd->errno_fd = std::exchange(fd_errno[1], -1);
} }
} }
OSTD_EXPORT void subprocess::reset() { OSTD_EXPORT void subprocess::reset() {
pid = -1; if (!p_current) {
if (errno_fd >= 0) { return;
::close(std::exchange(errno_fd, -1)); }
data *pd = static_cast<data *>(p_current);
if (pd->errno_fd >= 0) {
::close(pd->errno_fd);
}
p_current = nullptr;
}
OSTD_EXPORT void subprocess::move_data(subprocess &i) {
data *od = static_cast<data *>(i.p_current);
if (!od) {
return;
}
p_current = ::new (reinterpret_cast<void *>(&p_data)) data{*od};
i.p_current = nullptr;
}
OSTD_EXPORT void subprocess::swap_data(subprocess &i) {
if (!p_current) {
move_data(i);
} else if (!i.p_current) {
i.move_data(*this);
} else {
std::swap(
*static_cast<data *>(p_current), *static_cast<data *>(i.p_current)
);
} }
} }
OSTD_EXPORT int subprocess::close() { OSTD_EXPORT int subprocess::close() {
if (pid < 0) { if (!p_current) {
reset();
throw process_error{ECHILD, std::generic_category()}; throw process_error{ECHILD, std::generic_category()};
} }
data *pd = static_cast<data *>(p_current);
int retc = 0; int retc = 0;
if (pid_t wp; (wp = waitpid(pid, &retc, 0)) < 0) { if (pid_t wp; (wp = waitpid(pd->pid, &retc, 0)) < 0) {
reset(); reset();
throw process_error{errno, std::generic_category()}; throw process_error{errno, std::generic_category()};
} }
if (retc) { if (retc) {
int eno; int eno;
auto r = read(errno_fd, &eno, sizeof(int)); auto r = read(pd->errno_fd, &eno, sizeof(int));
reset(); reset();
if (r < 0) { if (r < 0) {
throw process_error{errno, std::generic_category()}; throw process_error{errno, std::generic_category()};
@ -295,14 +327,8 @@ OSTD_EXPORT int subprocess::close() {
throw process_error{eno, std::generic_category()}; throw process_error{eno, std::generic_category()};
} }
} }
return retc;
}
OSTD_EXPORT subprocess::~subprocess() {
try {
close();
} catch (process_error const &) {}
reset(); reset();
return retc;
} }
#else /* OSTD_PLATFORM_WIN32 */ #else /* OSTD_PLATFORM_WIN32 */
@ -317,10 +343,16 @@ OSTD_EXPORT int subprocess::close() {
throw process_error{ECHILD, std::generic_category()}; throw process_error{ECHILD, std::generic_category()};
} }
OSTD_EXPORT subprocess::~subprocess() { OSTD_EXPORT void subprocess::reset() {
return;
} }
#endif #endif
OSTD_EXPORT subprocess::~subprocess() {
try {
close();
} catch (process_error const &) {}
reset();
}
} /* namespace ostd */ } /* namespace ostd */