diff options
author | 2020-11-10 15:05:32 -0800 | |
---|---|---|
committer | 2020-12-07 17:09:12 -0800 | |
commit | 4e2b71fe7792843fc23e13d0201b59377888c3c5 (patch) | |
tree | 1218637a7c5111ebc75764f9d21fce8e56fb28f6 | |
parent | e21dbed979755c48581ce2600bdc9ce4b3bdc9ba (diff) |
FTL: Import std::future utilities from SF
Now including docs and expanded tests.
Bug: 160012986
Test: ftl_test
Change-Id: If9eb25646bb33ebc417ea87e6718b46fe0b87cf3
-rw-r--r-- | include/ftl/future.h | 109 | ||||
-rw-r--r-- | libs/ftl/Android.bp | 1 | ||||
-rw-r--r-- | libs/ftl/future_test.cpp | 105 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWC2.cpp | 9 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/HWComposer.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/Promise.h | 80 | ||||
-rw-r--r-- | services/surfaceflinger/RegionSamplingThread.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 15 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/Android.bp | 1 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/PromiseTest.cpp | 88 |
10 files changed, 231 insertions, 187 deletions
diff --git a/include/ftl/future.h b/include/ftl/future.h new file mode 100644 index 0000000000..dd6358fa7d --- /dev/null +++ b/include/ftl/future.h @@ -0,0 +1,109 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <future> +#include <type_traits> +#include <utility> + +namespace android::ftl { + +// Creates a future that defers a function call until its result is queried. +// +// auto future = ftl::defer([](int x) { return x + 1; }, 99); +// assert(future.get() == 100); +// +template <typename F, typename... Args> +inline auto defer(F&& f, Args&&... args) { + return std::async(std::launch::deferred, std::forward<F>(f), std::forward<Args>(args)...); +} + +// Creates a future that wraps a value. +// +// auto future = ftl::yield(42); +// assert(future.get() == 42); +// +// auto ptr = std::make_unique<char>('!'); +// auto future = ftl::yield(std::move(ptr)); +// assert(*future.get() == '!'); +// +template <typename T> +inline std::future<T> yield(T&& v) { + return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v)); +} + +namespace details { + +template <typename T> +struct future_result { + using type = T; +}; + +template <typename T> +struct future_result<std::future<T>> { + using type = T; +}; + +template <typename T> +using future_result_t = typename future_result<T>::type; + +// Attaches a continuation to a future. The continuation is a function that maps T to either R or +// std::future<R>. In the former case, the chain wraps the result in a future as if by ftl::yield. +// +// auto future = ftl::yield(123); +// std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')}; +// +// std::future<char> chain = +// ftl::chain(std::move(future)) +// .then([](int x) { return static_cast<std::size_t>(x % 2); }) +// .then([&futures](std::size_t i) { return std::move(futures[i]); }); +// +// assert(chain.get() == 'b'); +// +template <typename T> +struct Chain { + // Implicit conversion. + Chain(std::future<T>&& f) : future(std::move(f)) {} + operator std::future<T>&&() && { return std::move(future); } + + T get() && { return future.get(); } + + template <typename F, typename R = std::invoke_result_t<F, T>> + auto then(F&& op) && -> Chain<future_result_t<R>> { + return defer( + [](auto&& f, F&& op) { + R r = op(f.get()); + if constexpr (std::is_same_v<R, future_result_t<R>>) { + return r; + } else { + return r.get(); + } + }, + std::move(future), std::forward<F>(op)); + } + + std::future<T> future; +}; + +} // namespace details + +template <typename T> +inline auto chain(std::future<T>&& f) -> details::Chain<T> { + return std::move(f); +} + +} // namespace android::ftl diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 883d1388d1..5bccaca42d 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -5,6 +5,7 @@ cc_test { address: true, }, srcs: [ + "future_test.cpp", "small_map_test.cpp", "small_vector_test.cpp", "static_vector_test.cpp", diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp new file mode 100644 index 0000000000..9b3e93683f --- /dev/null +++ b/libs/ftl/future_test.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ftl/future.h> +#include <gtest/gtest.h> + +#include <algorithm> +#include <future> +#include <string> +#include <thread> +#include <vector> + +namespace android::test { + +// Keep in sync with example usage in header file. +TEST(Future, Example) { + { + auto future = ftl::defer([](int x) { return x + 1; }, 99); + EXPECT_EQ(future.get(), 100); + } + { + auto future = ftl::yield(42); + EXPECT_EQ(future.get(), 42); + } + { + auto ptr = std::make_unique<char>('!'); + auto future = ftl::yield(std::move(ptr)); + EXPECT_EQ(*future.get(), '!'); + } + { + auto future = ftl::yield(123); + std::future<char> futures[] = {ftl::yield('a'), ftl::yield('b')}; + + std::future<char> chain = ftl::chain(std::move(future)) + .then([](int x) { return static_cast<size_t>(x % 2); }) + .then([&futures](size_t i) { return std::move(futures[i]); }); + + EXPECT_EQ(chain.get(), 'b'); + } +} + +namespace { + +using ByteVector = std::vector<uint8_t>; + +ByteVector decrement(ByteVector bytes) { + std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; }); + return bytes; +} + +} // namespace + +TEST(Future, Chain) { + std::packaged_task<const char*()> fetch_string([] { return "ifmmp-"; }); + + std::packaged_task<ByteVector(std::string)> append_string([](std::string str) { + str += "!xpsme"; + return ByteVector{str.begin(), str.end()}; + }); + + std::packaged_task<std::future<ByteVector>(ByteVector)> decrement_bytes( + [](ByteVector bytes) { return ftl::defer(decrement, std::move(bytes)); }); + + auto fetch = fetch_string.get_future(); + std::thread fetch_thread(std::move(fetch_string)); + + std::thread append_thread, decrement_thread; + + EXPECT_EQ( + "hello, world", + ftl::chain(std::move(fetch)) + .then([](const char* str) { return std::string(str); }) + .then([&](std::string str) { + auto append = append_string.get_future(); + append_thread = std::thread(std::move(append_string), std::move(str)); + return append; + }) + .then([&](ByteVector bytes) { + auto decrement = decrement_bytes.get_future(); + decrement_thread = std::thread(std::move(decrement_bytes), std::move(bytes)); + return decrement; + }) + .then([](std::future<ByteVector> bytes) { return bytes; }) + .then([](const ByteVector& bytes) { return std::string(bytes.begin(), bytes.end()); }) + .get()); + + fetch_thread.join(); + append_thread.join(); + decrement_thread.join(); +} + +} // namespace android::test diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index e6bff04601..426092dc11 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -26,18 +26,17 @@ #include "HWC2.h" +#include <android/configuration.h> +#include <ftl/future.h> #include <ui/Fence.h> #include <ui/FloatRect.h> #include <ui/GraphicBuffer.h> -#include <android/configuration.h> - -#include <inttypes.h> #include <algorithm> +#include <cinttypes> #include <iterator> #include <set> -#include "../Promise.h" #include "ComposerHal.h" namespace android { @@ -647,7 +646,7 @@ Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests } std::future<Error> Display::setDisplayBrightness(float brightness) { - return promise::defer([composer = &mComposer, id = mId, brightness] { + return ftl::defer([composer = &mComposer, id = mId, brightness] { const auto intError = composer->setDisplayBrightness(id, brightness); return static_cast<Error>(intError); }); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 1548d18652..5fa72b83fc 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -30,6 +30,7 @@ #include <compositionengine/Output.h> #include <compositionengine/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> +#include <ftl/future.h> #include <log/log.h> #include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> @@ -37,7 +38,6 @@ #include <utils/Trace.h> #include "../Layer.h" // needed only for debugging -#include "../Promise.h" #include "../SurfaceFlinger.h" #include "../SurfaceFlingerProperties.h" #include "ComposerHal.h" @@ -792,10 +792,10 @@ status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t std::future<status_t> HWComposer::setDisplayBrightness(PhysicalDisplayId displayId, float brightness) { - RETURN_IF_INVALID_DISPLAY(displayId, promise::yield<status_t>(BAD_INDEX)); + RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; - return promise::chain(display->setDisplayBrightness(brightness)) + return ftl::chain(display->setDisplayBrightness(brightness)) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); diff --git a/services/surfaceflinger/Promise.h b/services/surfaceflinger/Promise.h deleted file mode 100644 index a80d441a4b..0000000000 --- a/services/surfaceflinger/Promise.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <future> -#include <type_traits> -#include <utility> - -namespace android::promise { -namespace impl { - -template <typename T> -struct FutureResult { - using Type = T; -}; - -template <typename T> -struct FutureResult<std::future<T>> { - using Type = T; -}; - -} // namespace impl - -template <typename T> -using FutureResult = typename impl::FutureResult<T>::Type; - -template <typename... Args> -inline auto defer(Args... args) { - return std::async(std::launch::deferred, std::forward<Args>(args)...); -} - -template <typename T> -inline std::future<T> yield(T&& v) { - return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v)); -} - -template <typename T> -struct Chain { - Chain(std::future<T>&& f) : future(std::move(f)) {} - operator std::future<T>&&() && { return std::move(future); } - - T get() && { return future.get(); } - - template <typename F, typename R = std::invoke_result_t<F, T>> - auto then(F&& op) && -> Chain<FutureResult<R>> { - return defer( - [](auto&& f, F&& op) { - R r = op(f.get()); - if constexpr (std::is_same_v<R, FutureResult<R>>) { - return r; - } else { - return r.get(); - } - }, - std::move(future), std::forward<F>(op)); - } - - std::future<T> future; -}; - -template <typename T> -inline Chain<T> chain(std::future<T>&& f) { - return std::move(f); -} - -} // namespace android::promise diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 2511eb37b3..ad4877bdeb 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -28,6 +28,7 @@ #include <compositionengine/Display.h> #include <compositionengine/impl/OutputCompositionState.h> #include <cutils/properties.h> +#include <ftl/future.h> #include <gui/IRegionSamplingListener.h> #include <gui/SyncScreenCaptureListener.h> #include <ui/DisplayStatInfo.h> @@ -38,7 +39,6 @@ #include "DisplayDevice.h" #include "DisplayRenderArea.h" #include "Layer.h" -#include "Promise.h" #include "Scheduler/VsyncController.h" #include "SurfaceFlinger.h" @@ -389,7 +389,7 @@ void RegionSamplingThread::captureSample() { const Rect sampledBounds = sampleRegion.bounds(); - SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] { + SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(), sampledBounds.getSize(), ui::Dataspace::V0_SRGB, orientation); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2fb362611f..f067922af3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -47,8 +47,7 @@ #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> -#include <dlfcn.h> -#include <errno.h> +#include <ftl/future.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IDisplayEventConnection.h> @@ -81,6 +80,7 @@ #include <utils/misc.h> #include <algorithm> +#include <cerrno> #include <cinttypes> #include <cmath> #include <cstdint> @@ -112,7 +112,6 @@ #include "LayerVector.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" -#include "Promise.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSyncSource.h" @@ -1502,12 +1501,12 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, f return BAD_VALUE; } - return promise::chain(schedule([=]() MAIN_THREAD { + return ftl::chain(schedule([=]() MAIN_THREAD { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { return getHwComposer().setDisplayBrightness(*displayId, brightness); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return promise::yield<status_t>(NAME_NOT_FOUND); + return ftl::yield<status_t>(NAME_NOT_FOUND); } })) .then([](std::future<status_t> task) { return task; }) @@ -5484,7 +5483,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, } } - RenderAreaFuture renderAreaFuture = promise::defer([=] { + RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace, args.useIdentityTransform, args.captureSecureLayers); }); @@ -5518,7 +5517,7 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack, pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode); } - RenderAreaFuture renderAreaFuture = promise::defer([=] { + RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace, false /* useIdentityTransform */, false /* captureSecureLayers */); @@ -5622,7 +5621,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } bool childrenOnly = args.childrenOnly; - RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> { + RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> { return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace, childrenOnly, layerStackSpaceRect, captureSecureLayers); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 871222c8b0..20f8f4212d 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -50,7 +50,6 @@ cc_test { "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", "MessageQueueTest.cpp", - "PromiseTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp deleted file mode 100644 index e4dc1fedb1..0000000000 --- a/services/surfaceflinger/tests/unittests/PromiseTest.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <algorithm> -#include <future> -#include <string> -#include <thread> -#include <vector> - -#include <gtest/gtest.h> - -#include "Promise.h" - -namespace android { -namespace { - -using Bytes = std::vector<uint8_t>; - -Bytes decrement(Bytes bytes) { - std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; }); - return bytes; -} - -} // namespace - -TEST(PromiseTest, yield) { - EXPECT_EQ(42, promise::yield(42).get()); - - auto ptr = std::make_unique<char>('!'); - auto future = promise::yield(std::move(ptr)); - EXPECT_EQ('!', *future.get()); -} - -TEST(PromiseTest, chain) { - std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; }); - - std::packaged_task<Bytes(std::string)> appendString([](std::string str) { - str += "!xpsme"; - return Bytes{str.begin(), str.end()}; - }); - - std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes( - [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); }); - - auto fetch = fetchString.get_future(); - std::thread fetchThread(std::move(fetchString)); - - std::thread appendThread, decrementThread; - - EXPECT_EQ("hello, world", - promise::chain(std::move(fetch)) - .then([](const char* str) { return std::string(str); }) - .then([&](std::string str) { - auto append = appendString.get_future(); - appendThread = std::thread(std::move(appendString), std::move(str)); - return append; - }) - .then([&](Bytes bytes) { - auto decrement = decrementBytes.get_future(); - decrementThread = std::thread(std::move(decrementBytes), - std::move(bytes)); - return decrement; - }) - .then([](std::future<Bytes> bytes) { return bytes; }) - .then([](const Bytes& bytes) { - return std::string(bytes.begin(), bytes.end()); - }) - .get()); - - fetchThread.join(); - appendThread.join(); - decrementThread.join(); -} - -} // namespace android |