diff --git a/examples/client.cpp b/examples/client.cpp index 9ce1884..47696f2 100644 --- a/examples/client.cpp +++ b/examples/client.cpp @@ -33,8 +33,7 @@ int main(int argc, char** argv) { alpha::ResourceHandle resource = client.makeResourceHandle(g_address, g_provider_id); - int32_t result; - resource.computeSum(32, 54, &result); + int32_t result = resource.computeSum(32, 54).wait(); } catch(const alpha::Exception& ex) { std::cerr << ex.what() << std::endl; diff --git a/include/alpha/AsyncRequest.hpp b/include/alpha/AsyncRequest.hpp deleted file mode 100644 index bb5ffad..0000000 --- a/include/alpha/AsyncRequest.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * (C) 2020 The University of Chicago - * - * See COPYRIGHT in top-level directory. - */ -#ifndef __ALPHA_ASYNC_REQUEST_HPP -#define __ALPHA_ASYNC_REQUEST_HPP - -#include -#include - -namespace alpha { - -class AsyncRequestImpl; -class ResourceHandle; - -/** - * @brief AsyncRequest objects are used to keep track of - * on-going asynchronous operations. - */ -class AsyncRequest { - - friend ResourceHandle; - - public: - - /** - * @brief Default constructor. Will create a non-valid AsyncRequest. - */ - AsyncRequest(); - - /** - * @brief Copy constructor. - */ - AsyncRequest(const AsyncRequest& other); - - /** - * @brief Move constructor. - */ - AsyncRequest(AsyncRequest&& other); - - /** - * @brief Copy-assignment operator. - */ - AsyncRequest& operator=(const AsyncRequest& other); - - /** - * @brief Move-assignment operator. - */ - AsyncRequest& operator=(AsyncRequest&& other); - - /** - * @brief Destructor. - */ - ~AsyncRequest(); - - /** - * @brief Wait for the request to complete. - */ - void wait() const; - - /** - * @brief Test if the request has completed, without blocking. - */ - bool completed() const; - - /** - * @brief Checks if the object is valid. - */ - operator bool() const; - - private: - - std::shared_ptr self; - - AsyncRequest(const std::shared_ptr& impl); - -}; - -} - -#endif diff --git a/include/alpha/Future.hpp b/include/alpha/Future.hpp new file mode 100644 index 0000000..69a9c99 --- /dev/null +++ b/include/alpha/Future.hpp @@ -0,0 +1,84 @@ +/* + * (C) 2024 The University of Chicago + * + * See COPYRIGHT in top-level directory. + */ +#ifndef __ALPHA_FUTURE_HPP +#define __ALPHA_FUTURE_HPP + +#include +#include +#include +#include +#include + +namespace alpha { + +/** + * @brief Future objects are used to keep track of + * on-going asynchronous operations. + */ +template +class Future { + + public: + + /** + * @brief Copy constructor. + */ + Future() = default; + + /** + * @brief Copy constructor. + */ + Future(const Future& other) = default; + + /** + * @brief Move constructor. + */ + Future(Future&& other) = default; + + /** + * @brief Copy-assignment operator. + */ + Future& operator=(const Future& other) = default; + + /** + * @brief Move-assignment operator. + */ + Future& operator=(Future&& other) = default; + + /** + * @brief Destructor. + */ + ~Future() = default; + + /** + * @brief Wait for the request to complete. + */ + T wait() { + Result result = m_resp.wait(); + return std::move(result).valueOrThrow(); + } + + /** + * @brief Test if the request has completed, without blocking. + */ + bool completed() const { + return m_resp.received(); + } + + /** + * @brief Constructor. + */ + Future(thallium::async_response resp) + : m_resp(std::move(resp)) {} + + private: + + thallium::async_response m_resp; +}; + +} + +#endif diff --git a/include/alpha/ResourceHandle.hpp b/include/alpha/ResourceHandle.hpp index 43c1dec..9378ec8 100644 --- a/include/alpha/ResourceHandle.hpp +++ b/include/alpha/ResourceHandle.hpp @@ -12,12 +12,10 @@ #include #include #include -#include +#include namespace alpha { -namespace tl = thallium; - class Client; class ResourceHandleImpl; @@ -80,12 +78,10 @@ class ResourceHandle { * * @param[in] x first integer * @param[in] y second integer - * @param[out] result result - * @param[out] req request for a non-blocking operation + * + * @return a Future that can be awaited to get the result. */ - void computeSum(int32_t x, int32_t y, - int32_t* result = nullptr, - AsyncRequest* req = nullptr) const; + Future computeSum(int32_t x, int32_t y) const; private: diff --git a/include/alpha/Result.hpp b/include/alpha/Result.hpp index 867bac7..352925d 100644 --- a/include/alpha/Result.hpp +++ b/include/alpha/Result.hpp @@ -1,11 +1,12 @@ /* - * (C) 2020 The University of Chicago + * (C) 2024 The University of Chicago * * See COPYRIGHT in top-level directory. */ #ifndef __ALPHA_RESULT_HPP #define __ALPHA_RESULT_HPP +#include #include #include @@ -30,13 +31,42 @@ namespace alpha { template class Result { + template + friend class Result; + public: Result() = default; - Result(Result&&) = default; - Result(const Result&) = default; - Result& operator=(Result&&) = default; - Result& operator=(const Result&) = default; + + template + Result(Result&& other) + : m_success{other.m_success} + , m_error{std::move(other.m_error)} + , m_value{std::move(other.m_value)} {} + + template + Result(const Result& other) + : m_success{other.m_success} + , m_error{other.m_error} + , m_value{other.m_value} {} + + template + Result& operator=(Result&& other) { + if(this == reinterpret_cast(&other)) return *this; + m_success = other.m_success; + m_error = std::move(other.m_error); + m_value = std::move(other.m_value); + return *this; + } + + template + Result& operator=(const Result& other) { + if(this == reinterpret_cast(&other)) return *this; + m_success = other.m_success; + m_error = other.m_error; + m_value = other.m_value; + return *this; + } /** * @brief Whether the request succeeded. diff --git a/src/AsyncRequest.cpp b/src/AsyncRequest.cpp deleted file mode 100644 index de6a0d0..0000000 --- a/src/AsyncRequest.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * (C) 2020 The University of Chicago - * - * See COPYRIGHT in top-level directory. - */ -#include "alpha/Exception.hpp" -#include "alpha/AsyncRequest.hpp" -#include "AsyncRequestImpl.hpp" - -namespace alpha { - -AsyncRequest::AsyncRequest() = default; - -AsyncRequest::AsyncRequest(const std::shared_ptr& impl) -: self(impl) {} - -AsyncRequest::AsyncRequest(const AsyncRequest& other) = default; - -AsyncRequest::AsyncRequest(AsyncRequest&& other) { - self = std::move(other.self); - other.self = nullptr; -} - -AsyncRequest::~AsyncRequest() { - if(self && self.unique()) { - wait(); - } -} - -AsyncRequest& AsyncRequest::operator=(const AsyncRequest& other) { - if(this == &other || self == other.self) return *this; - if(self && self.unique()) { - wait(); - } - self = other.self; - return *this; -} - -AsyncRequest& AsyncRequest::operator=(AsyncRequest&& other) { - if(this == &other || self == other.self) return *this; - if(self && self.unique()) { - wait(); - } - self = std::move(other.self); - other.self = nullptr; - return *this; -} - -void AsyncRequest::wait() const { - if(not self) throw Exception("Invalid alpha::AsyncRequest object"); - if(self->m_waited) return; - self->m_wait_callback(*self); - self->m_waited = true; -} - -bool AsyncRequest::completed() const { - if(not self) throw Exception("Invalid alpha::AsyncRequest object"); - return self->m_async_response.received(); -} - -} diff --git a/src/AsyncRequestImpl.hpp b/src/AsyncRequestImpl.hpp deleted file mode 100644 index c5df97e..0000000 --- a/src/AsyncRequestImpl.hpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * (C) 2020 The University of Chicago - * - * See COPYRIGHT in top-level directory. - */ -#ifndef __ALPHA_ASYNC_REQUEST_IMPL_H -#define __ALPHA_ASYNC_REQUEST_IMPL_H - -#include -#include - -namespace alpha { - -namespace tl = thallium; - -struct AsyncRequestImpl { - - AsyncRequestImpl(tl::async_response&& async_response) - : m_async_response(std::move(async_response)) {} - - tl::async_response m_async_response; - bool m_waited = false; - std::function m_wait_callback; - -}; - -} - -#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 16f0229..ee17665 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,8 +5,7 @@ set (server-src-files set (client-src-files Client.cpp - ResourceHandle.cpp - AsyncRequest.cpp) + ResourceHandle.cpp) set (dummy-src-files dummy/DummyBackend.cpp) diff --git a/src/ResourceHandle.cpp b/src/ResourceHandle.cpp index a4e1bbf..7b7d734 100644 --- a/src/ResourceHandle.cpp +++ b/src/ResourceHandle.cpp @@ -7,7 +7,6 @@ #include "alpha/Result.hpp" #include "alpha/Exception.hpp" -#include "AsyncRequestImpl.hpp" #include "ClientImpl.hpp" #include "ResourceHandleImpl.hpp" @@ -39,29 +38,14 @@ Client ResourceHandle::client() const { return Client(self->m_client); } -void ResourceHandle::computeSum( - int32_t x, int32_t y, - int32_t* sum, - AsyncRequest* req) const +Future ResourceHandle::computeSum( + int32_t x, int32_t y) const { if(not self) throw Exception("Invalid alpha::ResourceHandle object"); auto& rpc = self->m_client->m_compute_sum; auto& ph = self->m_ph; - if(req == nullptr) { // synchronous call - Result response = rpc.on(ph)(x, y); - response.andThen([sum](int32_t s) { if(sum) *sum = s; }); - } else { // asynchronous call - auto async_response = rpc.on(ph).async(x, y); - auto async_request_impl = - std::make_shared(std::move(async_response)); - async_request_impl->m_wait_callback = - [sum](AsyncRequestImpl& async_request_impl) { - Result response = - async_request_impl.m_async_response.wait(); - response.andThen([sum](int32_t s) { if(sum) *sum = s; }); - }; - *req = AsyncRequest(std::move(async_request_impl)); - } + auto async_response = rpc.on(ph).async(x, y); + return Future{std::move(async_response)}; } } diff --git a/tests/ResourceTest.cpp b/tests/ResourceTest.cpp index 25724d5..2aeff2d 100644 --- a/tests/ResourceTest.cpp +++ b/tests/ResourceTest.cpp @@ -29,16 +29,9 @@ TEST_CASE("Resource test", "[resource]") { auto rh = client.makeResourceHandle(addr, 42); SECTION("Send Sum RPC") { - int32_t result = 0; - REQUIRE_NOTHROW(rh.computeSum(42, 51, &result)); + int32_t result; + REQUIRE_NOTHROW([&]() { result = rh.computeSum(42, 51).wait(); }()); REQUIRE(result == 93); - - REQUIRE_NOTHROW(rh.computeSum(42, 51)); - - alpha::AsyncRequest request; - REQUIRE_NOTHROW(rh.computeSum(42, 52, &result, &request)); - REQUIRE_NOTHROW(request.wait()); - REQUIRE(result == 94); } } }