inline bool wait_for( child_handle &p, int & exit_code, const std::chrono::duration<Rep, Period>& rel_time) { std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); ::boost::detail::winapi::DWORD_ wait_code; wait_code = ::boost::detail::winapi::WaitForSingleObject(p.process_handle(), static_cast<::boost::detail::winapi::DWORD_>(ms.count())); if (wait_code == ::boost::detail::winapi::wait_failed) throw_last_error("WaitForSingleObject() failed"); else if (wait_code == ::boost::detail::winapi::wait_timeout) return false; // ::boost::detail::winapi::DWORD_ _exit_code; if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) throw_last_error("GetExitCodeProcess() failed"); exit_code = static_cast<int>(_exit_code); ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; return true; }
inline void wait(child_handle &p, int & exit_code) { if (::boost::detail::winapi::WaitForSingleObject(p.process_handle(), ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) throw_last_error("WaitForSingleObject() failed"); ::boost::detail::winapi::DWORD_ _exit_code; if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &_exit_code)) throw_last_error("GetExitCodeProcess() failed"); ::boost::detail::winapi::CloseHandle(p.proc_info.hProcess); p.proc_info.hProcess = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; exit_code = static_cast<int>(_exit_code); }
bool in_group() const { ::boost::detail::winapi::BOOL_ value; if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value)) throw_last_error("IsProcessinJob Failed"); return value!=0; }
inline void wait(const group_handle &p) { if (::boost::detail::winapi::WaitForSingleObject(p.handle(), ::boost::detail::winapi::infinite) == ::boost::detail::winapi::wait_failed) throw_last_error("WaitForSingleObject() failed"); }
inline bool in_group() { ::boost::winapi::BOOL_ res; if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res)) throw_last_error("IsProcessInJob failed"); return res!=0; }
bool has(handle_t proc) { ::boost::winapi::BOOL_ is; if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is)) throw_last_error(); return is!=0; }
AttributeHandleList::AttributeHandleList(std::vector<HANDLE> handle_list) : m_handle_store(nullptr), m_pAttributeList(nullptr, attribute_list_deleter) { size_t size = 0; BOOL ok = ::InitializeProcThreadAttributeList(NULL, 1, 0, &size) || ::GetLastError() == ERROR_INSUFFICIENT_BUFFER; if (!ok) throw_last_error("InitializeProcThreadAttributeList(NULL, ...) failed"); m_pAttributeList.reset(reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new char[size])); ok = ::InitializeProcThreadAttributeList(m_pAttributeList.get(), 1, 0, &size); if (!ok) { delete[] reinterpret_cast<char*>(m_pAttributeList.release()); throw_last_error("InitializeProcThreadAttributeList() failed"); } // WARNING: O(n^2), ok for small lists: for (size_t i = 0; i < handle_list.size(); i++) { size_t next = i + 1; while (1) { auto it = std::find(handle_list.begin() + next, handle_list.end(), handle_list.at(i)); if (it == handle_list.end()) break; next = it - handle_list.begin(); handle_list.erase(it); } } m_handle_store.reset(new HANDLE[handle_list.size()]); if (handle_list.size()) { // C++ is evil: // data() is not undefined behavior even if handle_list is empty, // however it is allowed to be nullptr in this case, while memcpy // requires the src to never be nullptr, even for a zero size. std::memcpy(m_handle_store.get(), handle_list.data(), handle_list.size() * sizeof(HANDLE)); } ok = ::UpdateProcThreadAttribute(m_pAttributeList.get(), 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, (PVOID)m_handle_store.get(), handle_list.size() * sizeof(HANDLE), NULL, NULL); if (!ok) throw_last_error("UpdateProcThreadAttribute() failed"); }
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p) { auto proc = ::boost::detail::winapi::GetCurrentProcess(); if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::detail::winapi::DuplicateHandle( proc, p._source, proc, &_source, 0, static_cast<::boost::detail::winapi::BOOL_>(true), ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_) _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_; else if (!::boost::detail::winapi::DuplicateHandle( proc, p._sink, proc, &_sink, 0, static_cast<::boost::detail::winapi::BOOL_>(true), ::boost::detail::winapi::DUPLICATE_SAME_ACCESS_)) throw_last_error("Duplicate Pipe Failed"); }
explicit child_handle(pid_t pid) : proc_info{nullptr, nullptr, 0,0} { auto h = ::boost::detail::winapi::OpenProcess( ::boost::detail::winapi::PROCESS_ALL_ACCESS_, static_cast<::boost::detail::winapi::BOOL_>(0), pid); if (h == nullptr) throw_last_error("OpenProcess() failed"); proc_info.hProcess = h; proc_info.dwProcessId = pid; }
inline void associate_completion_port(::boost::winapi::HANDLE_ job, ::boost::winapi::HANDLE_ io_port) { workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port; port.CompletionKey = job; port.CompletionPort = io_port; if (!workaround::set_information_job_object( job, workaround::JobObjectAssociateCompletionPortInformation_, static_cast<void*>(&port), sizeof(port))) throw_last_error("SetInformationJobObject() failed"); }
inline bool break_away_enabled(::boost::winapi::HANDLE_ h) { workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; if (!workaround::query_information_job_object( h, workaround::JobObjectExtendedLimitInformation_, static_cast<void*>(&info), sizeof(info), nullptr)) throw_last_error("QueryInformationJobObject() failed"); return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0; }
static HANDLE open_inheritable_nul(bool output) { SECURITY_ATTRIBUTES sec_attr = { sizeof(sec_attr), NULL, TRUE }; HANDLE hret = ::CreateFileA("nul", output ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_attr, OPEN_EXISTING, 0, NULL); if (hret == NULL || hret == INVALID_HANDLE_VALUE) throw_last_error("CreateFile(\"nul\",...) failed"); return hret; }
inline bool wait_for( const group_handle &p, const std::chrono::duration<Rep, Period>& rel_time) { std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(rel_time); ::boost::detail::winapi::DWORD_ wait_code; wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); if (wait_code == ::boost::detail::winapi::wait_failed) throw_last_error("WaitForSingleObject() failed"); else if (wait_code == ::boost::detail::winapi::wait_timeout) return false; // return true; }
inline bool wait_until( const group_handle &p, const std::chrono::time_point<Clock, Duration>& timeout_time) { std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>( timeout_time - std::chrono::system_clock::now()); ::boost::detail::winapi::DWORD_ wait_code; wait_code = ::boost::detail::winapi::WaitForSingleObject(p.handle(), ms.count()); if (wait_code == ::boost::detail::winapi::wait_failed) throw_last_error("WaitForSingleObject() failed"); else if (wait_code == ::boost::detail::winapi::wait_timeout) return false; // return true; }
void add(handle_t proc) { if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc)) throw_last_error(); }
basic_pipe() { if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0)) throw_last_error("CreatePipe() failed"); }