mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
Change uv::Async to accept data parameters
This is a breaking change as it makes Async a template (e.g. Async<> must be used instead of just Async). When data parameters are provided, an internal mutex and vector is used to hold the parameter packs until the loop runs.
This commit is contained in:
@@ -11,21 +11,99 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "wpi/STLExtras.h"
|
||||
#include "wpi/Signal.h"
|
||||
#include "wpi/mutex.h"
|
||||
#include "wpi/uv/Handle.h"
|
||||
#include "wpi/uv/Loop.h"
|
||||
|
||||
namespace wpi {
|
||||
namespace uv {
|
||||
|
||||
class Loop;
|
||||
|
||||
/**
|
||||
* Async handle.
|
||||
* Async handles allow the user to "wakeup" the event loop and have a signal
|
||||
* generated from another thread.
|
||||
*
|
||||
* Data may be passed into the callback called on the event loop by using
|
||||
* template parameters. If data parameters are used, the async callback will
|
||||
* be called once for every call to Send(). If no data parameters are used,
|
||||
* the async callback may or may not be called for every call to Send() (e.g.
|
||||
* the calls may be coaleasced).
|
||||
*/
|
||||
class Async final : public HandleImpl<Async, uv_async_t> {
|
||||
template <typename... T>
|
||||
class Async final : public HandleImpl<Async<T...>, uv_async_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
explicit Async(const private_init&) {}
|
||||
~Async() noexcept override = default;
|
||||
|
||||
/**
|
||||
* Create an async handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Async> Create(Loop& loop) {
|
||||
auto h = std::make_shared<Async>(private_init{});
|
||||
int err = uv_async_init(loop.GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
|
||||
auto& h = *static_cast<Async*>(handle->data);
|
||||
std::lock_guard<wpi::mutex> lock(h.m_mutex);
|
||||
for (auto&& v : h.m_data) apply_tuple(h.wakeup, v);
|
||||
h.m_data.clear();
|
||||
});
|
||||
if (err < 0) {
|
||||
loop.ReportError(err);
|
||||
return nullptr;
|
||||
}
|
||||
h->Keep();
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an async handle.
|
||||
*
|
||||
* @param loop Loop object where this handle runs.
|
||||
*/
|
||||
static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop) {
|
||||
return Create(*loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wakeup the event loop and emit the event.
|
||||
*
|
||||
* It’s safe to call this function from any thread EXCEPT the loop thread.
|
||||
* An async event will be emitted on the loop thread.
|
||||
*/
|
||||
template <typename... U>
|
||||
void Send(U&&... u) {
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
m_data.emplace_back(std::forward_as_tuple(std::forward<U>(u)...));
|
||||
}
|
||||
this->Invoke(&uv_async_send, this->GetRaw());
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal generated (on event loop thread) when the async event occurs.
|
||||
*/
|
||||
sig::Signal<T...> wakeup;
|
||||
|
||||
private:
|
||||
wpi::mutex m_mutex;
|
||||
std::vector<std::tuple<T...>> m_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Async specialization for no data parameters. The async callback may or may
|
||||
* not be called for every call to Send() (e.g. the calls may be coaleasced).
|
||||
*/
|
||||
template <>
|
||||
class Async<> final : public HandleImpl<Async<>, uv_async_t> {
|
||||
struct private_init {};
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user