blob: 0f7c7b64fa14fc4ba18b4a05e33dd11e5b3381a7 [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <boost/asio/io_context.hpp>
#include <functional>
#include <memory>
#include <queue>
#include <utility>
class SerialQueue : public std::enable_shared_from_this<SerialQueue>
{
public:
class ReleaseHandle
{
public:
ReleaseHandle() = default;
ReleaseHandle(const ReleaseHandle&) = delete;
ReleaseHandle& operator=(const ReleaseHandle&) = delete;
explicit ReleaseHandle(std::weak_ptr<SerialQueue> q) :
queue(std::move(q))
{}
ReleaseHandle(ReleaseHandle&& other) noexcept :
queue(std::move(other.queue))
{}
ReleaseHandle& operator=(ReleaseHandle&& other) noexcept
{
if (this != &other)
{
reset();
queue = std::move(other.queue);
}
return *this;
}
~ReleaseHandle()
{
reset();
}
private:
void reset();
std::weak_ptr<SerialQueue> queue;
};
using Task = std::move_only_function<void(ReleaseHandle)>;
explicit SerialQueue(boost::asio::io_context& io);
// Run the task now if the queue is idle; otherwise enqueue it. When
// dispatched, the task receives a move-only ReleaseHandle. The slot stays
// reserved until that handle is destroyed, so the task must keep the
// handle alive for as long as it considers itself "in flight" — typically
// by moving it into the capture list of any continuation lambda. Letting
// the handle fall out of scope is what releases the slot and dispatches the
// next queued task.
void submit(Task task);
private:
void release();
boost::asio::io_context& io;
bool inFlight{false};
std::queue<Task> pending;
};