#pragma once
#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <future>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
#include "../common/timer.h"
#include "xgboost/collective/result.h"
#include "xgboost/collective/socket.h"
namespace xgboost::collective {
class Loop {
public:
struct Op {
enum Code : std::int8_t { kRead = 0, kWrite = 1, kSleep = 3 } code;
std::int32_t rank{-1};
std::int8_t* ptr{nullptr};
std::size_t n{0};
TCPSocket* sock{nullptr};
std::size_t off{0};
std::shared_ptr<std::promise<void>> pr;
explicit Op(Code c) : code{c} { CHECK(c == kSleep); }
Op(Code c, std::int32_t rank, std::int8_t* ptr, std::size_t n, TCPSocket* sock, std::size_t off)
: code{c}, rank{rank}, ptr{ptr}, n{n}, sock{sock}, off{off} {}
Op(Op const&) = default;
Op& operator=(Op const&) = default;
Op(Op&&) = default;
Op& operator=(Op&&) = default;
[[nodiscard]] static Op Sleep(std::size_t seconds) {
Op op{kSleep};
op.n = seconds;
return op;
}
};
private:
std::thread worker_;
std::condition_variable cv_;
std::queue<Op> queue_; std::vector<std::future<void>> futures_;
std::mutex mu_;
std::chrono::seconds timeout_;
Result rc_;
std::mutex rc_lock_;
bool stop_{false};
std::exception_ptr curr_exce_{nullptr};
common::Monitor mutable timer_;
Result ProcessQueue(std::queue<Op>* p_queue) const;
void Process();
public:
Result Stop();
void Submit(Op op);
[[nodiscard]] Result Block();
explicit Loop(std::chrono::seconds timeout);
~Loop() noexcept(false) {
this->Stop();
}
};
}