diff --git a/wpiutil/src/main/native/cpp/uv/Poll.cpp b/wpiutil/src/main/native/cpp/uv/Poll.cpp index f22c82817c..8b608cbea3 100644 --- a/wpiutil/src/main/native/cpp/uv/Poll.cpp +++ b/wpiutil/src/main/native/cpp/uv/Poll.cpp @@ -34,6 +34,44 @@ std::shared_ptr Poll::CreateSocket(Loop& loop, uv_os_sock_t sock) { return h; } +void Poll::Reuse(int fd, std::function callback) { + if (IsClosing()) return; + if (!m_reuseData) m_reuseData = std::make_unique(); + m_reuseData->callback = callback; + m_reuseData->isSocket = false; + m_reuseData->fd = fd; + uv_close(GetRawHandle(), [](uv_handle_t* handle) { + Poll& h = *static_cast(handle->data); + if (!h.m_reuseData || h.m_reuseData->isSocket) return; // just in case + auto data = std::move(h.m_reuseData); + int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->fd); + if (err < 0) { + h.ReportError(err); + return; + } + data->callback(); + }); +} + +void Poll::ReuseSocket(uv_os_sock_t sock, std::function callback) { + if (IsClosing()) return; + if (!m_reuseData) m_reuseData = std::make_unique(); + m_reuseData->callback = callback; + m_reuseData->isSocket = true; + m_reuseData->sock = sock; + uv_close(GetRawHandle(), [](uv_handle_t* handle) { + Poll& h = *static_cast(handle->data); + if (!h.m_reuseData || !h.m_reuseData->isSocket) return; // just in case + auto data = std::move(h.m_reuseData); + int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->sock); + if (err < 0) { + h.ReportError(err); + return; + } + data->callback(); + }); +} + void Poll::Start(int events) { Invoke(&uv_poll_start, GetRaw(), events, [](uv_poll_t* handle, int status, int events) { diff --git a/wpiutil/src/main/native/include/wpi/uv/Poll.h b/wpiutil/src/main/native/include/wpi/uv/Poll.h index b8721accaa..fad00e4514 100644 --- a/wpiutil/src/main/native/include/wpi/uv/Poll.h +++ b/wpiutil/src/main/native/include/wpi/uv/Poll.h @@ -68,6 +68,30 @@ class Poll final : public HandleImpl { return CreateSocket(*loop, sock); } + /** + * Reuse this handle. This closes the handle, and after the close completes, + * reinitializes it (identically to Create) and calls the provided callback. + * Unlike Close(), it does NOT emit the closed signal, however, IsClosing() + * will return true until the callback is called. This does nothing if + * IsClosing() is true (e.g. if Close() was called). + * + * @param fd File descriptor + * @param callback Callback + */ + void Reuse(int fd, std::function callback); + + /** + * Reuse this handle. This closes the handle, and after the close completes, + * reinitializes it (identically to CreateSocket) and calls the provided + * callback. Unlike Close(), it does NOT emit the closed signal, however, + * IsClosing() will return true until the callback is called. This does + * nothing if IsClosing() is true (e.g. if Close() was called). + * + * @param sock Socket descriptor. + * @param callback Callback + */ + void ReuseSocket(uv_os_sock_t sock, std::function callback); + /** * Start polling the file descriptor. * @@ -85,6 +109,15 @@ class Poll final : public HandleImpl { * Signal generated when a poll event occurs. */ sig::Signal pollEvent; + + private: + struct ReuseData { + std::function callback; + bool isSocket; + int fd; + uv_os_sock_t sock; + }; + std::unique_ptr m_reuseData; }; } // namespace uv