/* SPDX-License-Identifier: GPL-3.0-or-later * Copyright © 2026 The TokTok team. */ #include "../public/tox_runner.hh" namespace tox::test { ToxRunner::ToxRunner(SimulatedNode &node, const Tox_Options *_Nullable options) : tox_(node.create_tox(options)) , node_(node) { if (tox_) { tox_events_init(tox_.get()); } node_.simulation().register_runner(); tick_listener_id_ = node_.simulation().register_tick_listener([this](uint64_t gen) { Message msg; msg.type = Message::Tick; msg.generation = gen; queue_.push(std::move(msg)); }); thread_ = std::thread([this] { loop(); }); } ToxRunner::~ToxRunner() { // Unregister first to prevent new ticks and update simulation counters node_.simulation().unregister_tick_listener(tick_listener_id_); node_.simulation().unregister_runner(); Message msg; msg.type = Message::Stop; queue_.push(std::move(msg)); if (thread_.joinable()) { thread_.join(); } } void ToxRunner::execute(std::function task) { Message msg; msg.type = Message::Task; msg.task = std::move(task); queue_.push(std::move(msg)); } std::vector ToxRunner::poll_events() { std::vector ret; ToxEventsPtr ptr; while (events_queue_.try_pop(ptr)) { ret.push_back(std::move(ptr)); ptr = nullptr; // Reset ptr to avoid use-after-move warning, although try_pop overwrites // it. } return ret; } void ToxRunner::pause() { if (!active_.exchange(false)) { return; } node_.simulation().unregister_tick_listener(tick_listener_id_); node_.simulation().unregister_runner(); tick_listener_id_ = -1; } void ToxRunner::resume() { if (active_.exchange(true)) { return; } node_.simulation().register_runner(); tick_listener_id_ = node_.simulation().register_tick_listener([this](uint64_t gen) { Message msg; msg.type = Message::Tick; msg.generation = gen; queue_.push(std::move(msg)); }); } void ToxRunner::loop() { while (true) { Message msg = queue_.pop(); // Blocking wait switch (msg.type) { case Message::Stop: return; case Message::Task: if (msg.task && tox_) { msg.task(tox_.get()); } break; case Message::Tick: { if (!tox_) { node_.simulation().tick_complete(); break; } // Run Tox Events Tox_Err_Events_Iterate err; Tox_Events *events = tox_events_iterate(tox_.get(), false, &err); if (events) { events_queue_.push(ToxEventsPtr(events)); } uint32_t interval = tox_iteration_interval(tox_.get()); node_.simulation().tick_complete(interval); break; } } } } } // namespace tox::test