#include "config.h" #include "utils/waitpid_queue.h" #include #include namespace utils { WaitpidQueue::WaitpidQueue() { m_worker = std::async(std::launch::async, [this]() { auto wait_time = 50ms; while (true) { if (!m_queue.empty()) { auto start_time = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start_time < wait_time) { if (m_should_shutdown.load(std::memory_order_acquire)) return; std::this_thread::sleep_for(50ms); if (m_wakeup_worker.load(std::memory_order_acquire)) break; } } else { m_wakeup_worker.wait(false, std::memory_order_acquire); } // Adds a small delay to allow new processes to finish if they're quickly spawned and // terminated. std::this_thread::sleep_for(50ms); std::set queue; { std::lock_guard guard(m_mutex); if (m_should_shutdown) return; if (m_queue.empty()) throw torrent::internal_error("WaitpidQueue worker thread woke up but queue is empty."); queue = m_queue; m_wakeup_worker.store(false, std::memory_order_release); } wait_time = std::min(10 * 1000ms, wait_time * 2); for (auto pid : queue) { if (::waitpid(pid, nullptr, WNOHANG) == 0) continue; { std::lock_guard guard(m_mutex); if (m_queue.erase(pid) != 1) throw torrent::internal_error("WaitpidQueue worker thread could not find pid in queue."); } wait_time = std::max(50ms, wait_time / 2); m_remaining.fetch_sub(1, std::memory_order_release); m_remaining.notify_all(); } } }); } // We don't wait for the worker thread to finish as waitpid isn't needed to be called on shutdown. WaitpidQueue::~WaitpidQueue() { { std::lock_guard guard(m_mutex); m_should_shutdown = true; } m_wakeup_worker.store(true, std::memory_order_release); m_wakeup_worker.notify_all(); } void WaitpidQueue::close_pid(pid_t pid) { if (pid < 0) throw torrent::internal_error("WaitpidQueue::close_pid() called with invalid pid."); m_remaining.fetch_add(1, std::memory_order_acquire); { std::lock_guard guard(m_mutex); m_queue.insert(pid); } m_wakeup_worker.store(true, std::memory_order_release); m_wakeup_worker.notify_all(); } void WaitpidQueue::wait_for(uint32_t max_remaining) { while (m_remaining.load(std::memory_order_acquire) > max_remaining) m_remaining.wait(max_remaining, std::memory_order_acquire); } } // namespace torrent::utils