Files
allwpilib/wpiutil/src/main/native/include/wpi/uv/Handle.h
Peter Johnson b2c3b2dd8e Use std::string_view and fmtlib across all libraries (#3402)
- Twine, StringRef, Format, and NativeFormatting have been removed
- Logging now uses fmtlib style formatting
- Nearly all uses of wpi::outs/errs have been replaced with fmt::print() or
std::puts()/std::fputs() (for unformatted strings).
- A wpi/fmt/raw_ostream.h header has been added to enable
fmt::print() with wpi::raw_ostream
2021-06-06 16:13:58 -07:00

298 lines
8.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef WPIUTIL_WPI_UV_HANDLE_H_
#define WPIUTIL_WPI_UV_HANDLE_H_
#include <uv.h>
#include <cstdlib>
#include <functional>
#include <memory>
#include <string_view>
#include <utility>
#include "wpi/Signal.h"
#include "wpi/uv/Buffer.h"
#include "wpi/uv/Error.h"
#include "wpi/uv/Loop.h"
namespace wpi::uv {
/**
* Handle.
* Handles are not moveable or copyable and cannot be directly constructed.
* This class provides shared_ptr ownership and shared_from_this.
* Use the specific handle type Create() functions to create handles.
*/
class Handle : public std::enable_shared_from_this<Handle> {
public:
using Type = uv_handle_type;
Handle(const Handle&) = delete;
Handle(Handle&&) = delete;
Handle& operator=(const Handle&) = delete;
Handle& operator=(Handle&&) = delete;
virtual ~Handle() noexcept;
/**
* Get the type of the handle.
*
* A base handle offers no functionality to promote it to the actual handle
* type. By means of this function, the type of the underlying handle as
* specified by Type is made available.
*
* @return The actual type of the handle.
*/
Type GetType() const noexcept { return m_uv_handle->type; }
/**
* Get the name of the type of the handle. E.g. "pipe" for pipe handles.
*/
std::string_view GetTypeName() const noexcept {
return uv_handle_type_name(m_uv_handle->type);
}
/**
* Get the loop where this handle runs.
*
* @return The loop.
*/
std::shared_ptr<Loop> GetLoop() const noexcept {
return GetLoopRef().shared_from_this();
}
/**
* Get the loop where this handle runs.
*
* @return The loop.
*/
Loop& GetLoopRef() const noexcept {
return *static_cast<Loop*>(m_uv_handle->loop->data);
}
/**
* Check if the handle is active.
*
* What _active_ means depends on the type of handle:
*
* * An AsyncHandle handle is always active and cannot be deactivated,
* except by closing it with uv_close().
* * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
* that deals with I/O - is active when it is doing something that involves
* I/O, like reading, writing, connecting, accepting new connections, etc.
* * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
* has been started with a call to `Start()`.
*
* Rule of thumb: if a handle of type `FooHandle` has a `Start()` member
* method, then its active from the moment that method is called. Likewise,
* `Stop()` deactivates the handle again.
*
* @return True if the handle is active, false otherwise.
*/
bool IsActive() const noexcept { return uv_is_active(m_uv_handle) != 0; }
/**
* Check if a handle is closing or closed.
*
* This function should only be used between the initialization of the
* handle and the arrival of the close callback.
*
* @return True if the handle is closing or closed, false otherwise.
*/
bool IsClosing() const noexcept {
return m_closed || uv_is_closing(m_uv_handle) != 0;
}
/**
* Request handle to be closed.
*
* This **must** be called on each handle before memory is released.
* In-progress requests are cancelled and this can result in error() being
* emitted.
*
* The handle will emit closed() when finished.
*/
void Close() noexcept;
/**
* Set if the loop is closing.
*
* This is set during EventLoopRunner.Stop(), and can be used for other cases
* to indicate the loop should be closing. For instance for a uv_walk loop can
* use this to close existing handles.
*
* @param loopClosing true to set the loop currently in closing stages.
*/
void SetLoopClosing(bool loopClosing) noexcept {
m_loopClosing = loopClosing;
}
/**
* Get the loop closing status.
*
* This can be used from closed() in order to tell if a closing loop is the
* reason for the close, or another reason.
*
* @return true if the loop is closing, otherwise false.
*/
bool IsLoopClosing() const noexcept { return m_loopClosing; }
/**
* Reference the given handle.
*
* References are idempotent, that is, if a handle is already referenced
* calling this function again will have no effect.
*/
void Reference() noexcept { uv_ref(m_uv_handle); }
/**
* Unreference the given handle.
*
* References are idempotent, that is, if a handle is not referenced calling
* this function again will have no effect.
*/
void Unreference() noexcept { uv_unref(m_uv_handle); }
/**
* Check if the given handle is referenced.
* @return True if the handle is referenced, false otherwise.
*/
bool HasReference() const noexcept { return uv_has_ref(m_uv_handle) != 0; }
/**
* Return the size of the underlying handle type.
* @return The size of the underlying handle type.
*/
size_t RawSize() const noexcept { return uv_handle_size(m_uv_handle->type); }
/**
* Get the underlying handle data structure.
*
* @return The underlying handle data structure.
*/
uv_handle_t* GetRawHandle() const noexcept { return m_uv_handle; }
/**
* Set the functions used for allocating and releasing buffers. The size
* passed to the allocator function is a "suggested" size--it's just an
* indication, not related in any way to the pending data to be read. The
* user is free to allocate the amount of memory they decide. For example,
* applications with custom allocation schemes may decide to use a different
* size which matches the memory chunks they already have for other purposes.
*
* @warning Be very careful changing the allocator after the loop has started
* running; there are no interlocks between this and buffers currently in
* flight.
*
* @param alloc Allocation function
* @param dealloc Deallocation function
*/
void SetBufferAllocator(std::function<Buffer(size_t)> alloc,
std::function<void(Buffer&)> dealloc) {
m_allocBuf = alloc;
m_freeBuf = dealloc;
}
/**
* Free a buffer. Uses the function provided to SetBufFree() or
* Buffer::Deallocate by default.
*
* @param buf The buffer
*/
void FreeBuf(Buffer& buf) const noexcept { m_freeBuf(buf); }
/**
* Gets user-defined data.
* @return User-defined data if any, nullptr otherwise.
*/
template <typename T = void>
std::shared_ptr<T> GetData() const {
return std::static_pointer_cast<T>(m_data);
}
/**
* Sets user-defined data.
* @param data User-defined arbitrary data.
*/
void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
/**
* Error signal
*/
sig::Signal<Error> error;
/**
* Closed signal
*/
sig::Signal<> closed;
/**
* Report an error.
* @param err Error code
*/
void ReportError(int err) const { error(Error(err)); }
protected:
explicit Handle(uv_handle_t* uv_handle) : m_uv_handle{uv_handle} {
m_uv_handle->data = this;
}
void Keep() noexcept { m_self = shared_from_this(); }
void Release() noexcept { m_self.reset(); }
void ForceClosed() noexcept { m_closed = true; }
static void AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf);
static void DefaultFreeBuf(Buffer& buf);
template <typename F, typename... Args>
bool Invoke(F&& f, Args&&... args) const {
auto err = std::forward<F>(f)(std::forward<Args>(args)...);
if (err < 0) {
ReportError(err);
}
return err == 0;
}
private:
std::shared_ptr<Handle> m_self;
uv_handle_t* m_uv_handle;
bool m_closed = false;
bool m_loopClosing = false;
std::function<Buffer(size_t)> m_allocBuf{&Buffer::Allocate};
std::function<void(Buffer&)> m_freeBuf{&DefaultFreeBuf};
std::shared_ptr<void> m_data;
};
/**
* Handle.
*/
template <typename T, typename U>
class HandleImpl : public Handle {
public:
std::shared_ptr<T> shared_from_this() {
return std::static_pointer_cast<T>(Handle::shared_from_this());
}
std::shared_ptr<const T> shared_from_this() const {
return std::static_pointer_cast<const T>(Handle::shared_from_this());
}
/**
* Get the underlying handle data structure.
*
* @return The underlying handle data structure.
*/
U* GetRaw() const noexcept {
return reinterpret_cast<U*>(this->GetRawHandle());
}
protected:
HandleImpl() : Handle{static_cast<uv_handle_t*>(std::malloc(sizeof(U)))} {}
};
} // namespace wpi::uv
#endif // WPIUTIL_WPI_UV_HANDLE_H_