зеркало из https://github.com/microsoft/xlang.git
Move C++/WinRT coroutine helpers to dedicated header and add support for DispatcherQueue to resume_foreground (#154)
This commit is contained in:
Родитель
21737c8553
Коммит
e1235bd3d5
|
@ -2,3 +2,4 @@
|
|||
* text eol=lf
|
||||
*.png -text
|
||||
*.onnx -text
|
||||
*.winmd -text
|
||||
|
|
|
@ -82,17 +82,17 @@ add_custom_command(OUTPUT ${generated_files}
|
|||
)
|
||||
|
||||
add_custom_command(OUTPUT ${component_winmd}
|
||||
COMMAND midlrt ${project_folder}\\component.idl /nomidl /winrt /winmd ${component_winmd} /metadata_dir ${project_folder} /reference ${project_folder}\\windows.winmd /h "nul"
|
||||
COMMAND midlrt ${project_folder}\\component.idl /nomidl /winrt /winmd ${component_winmd} /metadata_dir ${project_folder}\\metadata /reference ${project_folder}\\metadata\\Windows.Foundation.winmd /h "nul"
|
||||
DEPENDS ${project_folder}\\component.idl ${generated_files}
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${foundation_h}
|
||||
COMMAND ${cpp_exe} -in ${project_folder}\\windows.winmd -out ${generated_files} -verbose
|
||||
COMMAND ${cpp_exe} -in local -out ${generated_files} -verbose
|
||||
DEPENDS ${component_winmd} ${generated_files} cppwinrt
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${mogule_g_cpp}
|
||||
COMMAND ${cpp_exe} -in ${component_winmd} -ref ${project_folder}\\windows.winmd -include Component -out ${generated_files} -component -verbose -prefix -base -lib test -opt
|
||||
COMMAND ${cpp_exe} -in ${component_winmd} -ref local -include Component -out ${generated_files} -component -verbose -prefix -base -lib test -opt
|
||||
DEPENDS ${foundation_h} ${generated_files} cppwinrt
|
||||
)
|
||||
|
||||
|
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "winrt/base.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
template<bool B> bool static_require()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <windows.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "catch.hpp"
|
||||
#include <inspectable.h>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/coroutine.h"
|
||||
|
||||
struct __declspec(uuid("5040a5f4-796a-42ff-9f06-be89137a518f")) IBase : IUnknown
|
||||
{
|
||||
|
|
Двоичные данные
src/test/cpp/windows.winmd
Двоичные данные
src/test/cpp/windows.winmd
Двоичный файл не отображается.
|
@ -2871,11 +2871,7 @@ struct WINRT_EBO produce_dispatch_to_overridable<T, D, %>
|
|||
w.write(strings::base_reference_produce);
|
||||
}
|
||||
|
||||
w.write(strings::base_await);
|
||||
w.write(strings::base_std_async_action);
|
||||
w.write(strings::base_std_async_action_with_progress);
|
||||
w.write(strings::base_std_async_operation);
|
||||
w.write(strings::base_std_async_operation_with_progress);
|
||||
w.write(strings::base_async);
|
||||
}
|
||||
else if (namespace_name == "Windows.Foundation.Collections")
|
||||
{
|
||||
|
@ -2893,9 +2889,5 @@ struct WINRT_EBO produce_dispatch_to_overridable<T, D, %>
|
|||
{
|
||||
w.write(strings::base_xaml_typename);
|
||||
}
|
||||
else if (namespace_name == "Windows.UI.Core")
|
||||
{
|
||||
w.write(strings::base_resume_foreground);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace xlang
|
|||
w.write(strings::base_chrono);
|
||||
w.write(strings::base_security);
|
||||
w.write(strings::base_std_hash);
|
||||
w.write(strings::base_std_fire_and_forget);
|
||||
w.write(strings::base_reflect);
|
||||
w.write(strings::base_natvis);
|
||||
w.write(strings::base_version, XLANG_VERSION_STRING);
|
||||
|
@ -45,6 +44,31 @@ namespace xlang
|
|||
w.flush_to_file(settings.output_folder + settings.root + "/base.h");
|
||||
}
|
||||
|
||||
static void write_coroutine_h()
|
||||
{
|
||||
writer w;
|
||||
write_license(w);
|
||||
write_open_file_guard(w, "COROUTINE");
|
||||
|
||||
w.write(R"(
|
||||
#include <experimental/coroutine>
|
||||
#include "winrt/Windows.Foundation.h"
|
||||
#include "winrt/Windows.System.h"
|
||||
#include "winrt/Windows.UI.Core.h"
|
||||
)");
|
||||
|
||||
w.write(strings::base_coroutine);
|
||||
w.write(strings::base_coroutine_resume);
|
||||
w.write(strings::base_coroutine_action);
|
||||
w.write(strings::base_coroutine_action_with_progress);
|
||||
w.write(strings::base_coroutine_operation);
|
||||
w.write(strings::base_coroutine_operation_with_progress);
|
||||
w.write(strings::base_std_fire_and_forget);
|
||||
|
||||
write_close_file_guard(w);
|
||||
w.flush_to_file(settings.output_folder + settings.root + "/coroutine.h");
|
||||
}
|
||||
|
||||
static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members)
|
||||
{
|
||||
writer w;
|
||||
|
|
|
@ -212,6 +212,7 @@ namespace xlang
|
|||
if (settings.base)
|
||||
{
|
||||
write_base_h();
|
||||
write_coroutine_h();
|
||||
}
|
||||
|
||||
if (settings.component)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
namespace winrt::impl
|
||||
{
|
||||
inline bool is_sta() noexcept
|
||||
{
|
||||
int32_t aptType;
|
||||
int32_t aptTypeQualifier;
|
||||
return (error_ok == WINRT_CoGetApartmentType(&aptType, &aptTypeQualifier)) && ((aptType == 0 /*APTTYPE_STA*/) || (aptType == 3 /*APTTYPE_MAINSTA*/));
|
||||
}
|
||||
|
||||
template <typename Async>
|
||||
void blocking_suspend(Async const& async)
|
||||
{
|
||||
WINRT_ASSERT(!is_sta());
|
||||
|
||||
slim_mutex m;
|
||||
slim_condition_variable cv;
|
||||
bool completed = false;
|
||||
async.Completed([&](auto && ...)
|
||||
{
|
||||
{
|
||||
slim_lock_guard const guard(m);
|
||||
completed = true;
|
||||
}
|
||||
cv.notify_one();
|
||||
});
|
||||
|
||||
slim_lock_guard guard(m);
|
||||
cv.wait(m, [&] { return completed; });
|
||||
}
|
||||
}
|
|
@ -1,838 +0,0 @@
|
|||
|
||||
namespace winrt::impl
|
||||
{
|
||||
inline bool is_sta() noexcept
|
||||
{
|
||||
int32_t aptType;
|
||||
int32_t aptTypeQualifier;
|
||||
return (error_ok == WINRT_CoGetApartmentType(&aptType, &aptTypeQualifier)) && ((aptType == 0 /*APTTYPE_STA*/) || (aptType == 3 /*APTTYPE_MAINSTA*/));
|
||||
}
|
||||
|
||||
template <typename Async>
|
||||
void blocking_suspend(Async const& async)
|
||||
{
|
||||
WINRT_ASSERT(!is_sta());
|
||||
|
||||
slim_mutex m;
|
||||
slim_condition_variable cv;
|
||||
bool completed = false;
|
||||
async.Completed([&](auto&&...)
|
||||
{
|
||||
{
|
||||
slim_lock_guard const guard(m);
|
||||
completed = true;
|
||||
}
|
||||
cv.notify_one();
|
||||
});
|
||||
|
||||
slim_lock_guard guard(m);
|
||||
cv.wait(m, [&] { return completed; });
|
||||
}
|
||||
|
||||
template <typename Async>
|
||||
struct await_adapter
|
||||
{
|
||||
Async const& async;
|
||||
|
||||
bool await_ready() const
|
||||
{
|
||||
return async.Status() == Windows::Foundation::AsyncStatus::Completed;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
auto context = capture<IContextCallback>(WINRT_CoGetObjectContext);
|
||||
|
||||
async.Completed([handle, context = std::move(context)](auto const&, Windows::Foundation::AsyncStatus)
|
||||
{
|
||||
com_callback_args args{};
|
||||
args.data = handle.address();
|
||||
|
||||
auto callback = [](com_callback_args* args) noexcept -> int32_t
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(args->data)();
|
||||
return error_ok;
|
||||
};
|
||||
|
||||
check_hresult(context->ContextCallback(callback, &args, guid_of<impl::ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
|
||||
});
|
||||
}
|
||||
|
||||
auto await_resume() const
|
||||
{
|
||||
return async.GetResults();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
|
||||
namespace winrt::Windows::Foundation
|
||||
{
|
||||
inline impl::await_adapter<IAsyncAction> operator co_await(IAsyncAction const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TProgress>
|
||||
impl::await_adapter<IAsyncActionWithProgress<TProgress>> operator co_await(IAsyncActionWithProgress<TProgress> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TResult>
|
||||
impl::await_adapter<IAsyncOperation<TResult>> operator co_await(IAsyncOperation<TResult> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TResult, typename TProgress>
|
||||
impl::await_adapter<IAsyncOperationWithProgress<TResult, TProgress>> operator co_await(IAsyncOperationWithProgress<TResult, TProgress> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
[[nodiscard]] inline auto resume_background()
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
if (!WINRT_TrySubmitThreadpoolCallback(callback, handle.address(), nullptr))
|
||||
{
|
||||
throw_last_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(context)();
|
||||
}
|
||||
};
|
||||
|
||||
return awaitable{};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] auto resume_background(T&& context)
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(T&& context) : m_context(std::forward<T>(context))
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> resume)
|
||||
{
|
||||
m_resume = resume;
|
||||
|
||||
if (!WINRT_TrySubmitThreadpoolCallback(callback, this, nullptr))
|
||||
{
|
||||
throw_last_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context) noexcept
|
||||
{
|
||||
auto that = static_cast<awaitable*>(context);
|
||||
auto guard = that->m_context();
|
||||
that->m_resume();
|
||||
}
|
||||
|
||||
T&& m_context;
|
||||
std::experimental::coroutine_handle<> m_resume{ nullptr };
|
||||
};
|
||||
|
||||
return awaitable{ std::forward<T>(context) };
|
||||
}
|
||||
|
||||
struct apartment_context
|
||||
{
|
||||
apartment_context()
|
||||
{
|
||||
m_context.capture(WINRT_CoGetObjectContext);
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
impl::com_callback_args args{};
|
||||
args.data = handle.address();
|
||||
check_hresult(m_context->ContextCallback(callback, &args, guid_of<impl::ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static int32_t WINRT_CALL callback(impl::com_callback_args* args) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(args->data)();
|
||||
return impl::error_ok;
|
||||
}
|
||||
|
||||
com_ptr<impl::IContextCallback> m_context;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline auto resume_after(Windows::Foundation::TimeSpan duration)
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
explicit awaitable(Windows::Foundation::TimeSpan duration) noexcept :
|
||||
m_duration(duration)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return m_duration.count() <= 0;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle)
|
||||
{
|
||||
m_timer.attach(check_pointer(WINRT_CreateThreadpoolTimer(callback, handle.address(), nullptr)));
|
||||
int64_t relative_count = -m_duration.count();
|
||||
WINRT_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0);
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context, void*) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(context)();
|
||||
}
|
||||
|
||||
struct timer_traits
|
||||
{
|
||||
using type = impl::ptp_timer;
|
||||
|
||||
static void close(type value) noexcept
|
||||
{
|
||||
WINRT_CloseThreadpoolTimer(value);
|
||||
}
|
||||
|
||||
static constexpr type invalid() noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
handle_type<timer_traits> m_timer;
|
||||
Windows::Foundation::TimeSpan m_duration;
|
||||
};
|
||||
|
||||
return awaitable{ duration };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {})
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(void* handle, Windows::Foundation::TimeSpan timeout) noexcept :
|
||||
m_timeout(timeout),
|
||||
m_handle(handle)
|
||||
{}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return WINRT_WaitForSingleObject(m_handle, 0) == 0;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> resume)
|
||||
{
|
||||
m_resume = resume;
|
||||
m_wait.attach(check_pointer(WINRT_CreateThreadpoolWait(callback, this, nullptr)));
|
||||
int64_t relative_count = -m_timeout.count();
|
||||
int64_t* file_time = relative_count != 0 ? &relative_count : nullptr;
|
||||
WINRT_SetThreadpoolWait(m_wait.get(), m_handle, file_time);
|
||||
}
|
||||
|
||||
bool await_resume() const noexcept
|
||||
{
|
||||
return m_result == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context, void*, uint32_t result) noexcept
|
||||
{
|
||||
auto that = static_cast<awaitable*>(context);
|
||||
that->m_result = result;
|
||||
that->m_resume();
|
||||
}
|
||||
|
||||
struct wait_traits
|
||||
{
|
||||
using type = impl::ptp_wait;
|
||||
|
||||
static void close(type value) noexcept
|
||||
{
|
||||
WINRT_CloseThreadpoolWait(value);
|
||||
}
|
||||
|
||||
static constexpr type invalid() noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
handle_type<wait_traits> m_wait;
|
||||
Windows::Foundation::TimeSpan m_timeout;
|
||||
void* m_handle;
|
||||
uint32_t m_result{};
|
||||
std::experimental::coroutine_handle<> m_resume{ nullptr };
|
||||
};
|
||||
|
||||
return awaitable{ handle, timeout };
|
||||
}
|
||||
|
||||
struct overlapped_io
|
||||
{
|
||||
uintptr_t Internal;
|
||||
uintptr_t InternalHigh;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t Offset;
|
||||
uint32_t OffsetHigh;
|
||||
} s;
|
||||
void* Pointer;
|
||||
};
|
||||
void* hEvent;
|
||||
};
|
||||
|
||||
struct awaitable_base
|
||||
{
|
||||
static void WINRT_CALL callback(void*, void*, void* overlapped, uint32_t result, std::size_t, void*) noexcept
|
||||
{
|
||||
auto context = static_cast<awaitable_base*>(overlapped);
|
||||
context->m_result = result;
|
||||
context->m_resume();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
overlapped_io m_overlapped{};
|
||||
uint32_t m_result{};
|
||||
std::experimental::coroutine_handle<> m_resume{ nullptr };
|
||||
};
|
||||
|
||||
struct resumable_io
|
||||
{
|
||||
resumable_io(void* object) :
|
||||
m_io(check_pointer(WINRT_CreateThreadpoolIo(object, awaitable_base::callback, nullptr, nullptr)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
auto start(F callback)
|
||||
{
|
||||
struct awaitable : awaitable_base, F
|
||||
{
|
||||
awaitable(impl::ptp_io io, F callback) noexcept :
|
||||
F(callback),
|
||||
m_io(io)
|
||||
{}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> resume_handle)
|
||||
{
|
||||
m_resume = resume_handle;
|
||||
WINRT_StartThreadpoolIo(m_io);
|
||||
|
||||
try
|
||||
{
|
||||
(*this)(m_overlapped);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
WINRT_CancelThreadpoolIo(m_io);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t await_resume() const
|
||||
{
|
||||
if (m_result != 38 /*ERROR_HANDLE_EOF*/)
|
||||
{
|
||||
check_win32(m_result);
|
||||
}
|
||||
return static_cast<uint32_t>(m_overlapped.InternalHigh);
|
||||
}
|
||||
|
||||
impl::ptp_io m_io{};
|
||||
};
|
||||
|
||||
return awaitable(get(), callback);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
auto start_pending(F callback)
|
||||
{
|
||||
struct awaitable : awaitable_base, F
|
||||
{
|
||||
awaitable(impl::ptp_io io, F callback) noexcept :
|
||||
F(callback),
|
||||
m_io(io)
|
||||
{}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool await_suspend(std::experimental::coroutine_handle<> resume_handle)
|
||||
{
|
||||
m_resume = resume_handle;
|
||||
WINRT_StartThreadpoolIo(m_io);
|
||||
|
||||
try
|
||||
{
|
||||
bool const pending = (*this)(m_overlapped);
|
||||
|
||||
if (!pending)
|
||||
{
|
||||
WINRT_CancelThreadpoolIo(m_io);
|
||||
}
|
||||
|
||||
return pending;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
WINRT_CancelThreadpoolIo(m_io);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t await_resume() const
|
||||
{
|
||||
if (m_result != 38 /*ERROR_HANDLE_EOF*/)
|
||||
{
|
||||
check_win32(m_result);
|
||||
}
|
||||
return static_cast<uint32_t>(m_overlapped.InternalHigh);
|
||||
}
|
||||
|
||||
impl::ptp_io m_io{};
|
||||
};
|
||||
|
||||
return awaitable(get(), callback);
|
||||
}
|
||||
|
||||
impl::ptp_io get() const noexcept
|
||||
{
|
||||
return m_io.get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct io_traits
|
||||
{
|
||||
using type = impl::ptp_io;
|
||||
|
||||
static void close(type value) noexcept
|
||||
{
|
||||
WINRT_CloseThreadpoolIo(value);
|
||||
}
|
||||
|
||||
static constexpr type invalid() noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
handle_type<io_traits> m_io;
|
||||
};
|
||||
|
||||
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
|
||||
inline auto operator co_await(Windows::Foundation::TimeSpan duration)
|
||||
{
|
||||
return resume_after(duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct get_progress_token_t {};
|
||||
|
||||
inline get_progress_token_t get_progress_token() noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
struct get_cancellation_token_t {};
|
||||
|
||||
inline get_cancellation_token_t get_cancellation_token() noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
}
|
||||
|
||||
namespace winrt::impl
|
||||
{
|
||||
template <typename Promise>
|
||||
struct cancellation_token
|
||||
{
|
||||
cancellation_token(Promise* promise) noexcept : m_promise(promise)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
cancellation_token<Promise> await_resume() const noexcept
|
||||
{
|
||||
return*this;
|
||||
}
|
||||
|
||||
bool operator()() const noexcept
|
||||
{
|
||||
return m_promise->Status() == Windows::Foundation::AsyncStatus::Canceled;
|
||||
}
|
||||
|
||||
void callback(winrt::delegate<>&& cancel) noexcept
|
||||
{
|
||||
m_promise->cancellation_callback(std::move(cancel));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Promise * m_promise;
|
||||
};
|
||||
|
||||
template <typename Promise, typename Progress>
|
||||
struct progress_token
|
||||
{
|
||||
progress_token(Promise* promise) noexcept :
|
||||
m_promise(promise)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
progress_token<Promise, Progress> await_resume() const noexcept
|
||||
{
|
||||
return*this;
|
||||
}
|
||||
|
||||
void operator()(Progress const& result)
|
||||
{
|
||||
m_promise->set_progress(result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Promise * m_promise;
|
||||
};
|
||||
|
||||
template <typename Derived, typename AsyncInterface, typename CompletedHandler, typename TProgress = void>
|
||||
struct promise_base : implements<Derived, AsyncInterface, Windows::Foundation::IAsyncInfo>
|
||||
{
|
||||
using AsyncStatus = Windows::Foundation::AsyncStatus;
|
||||
|
||||
unsigned long WINRT_CALL Release() noexcept
|
||||
{
|
||||
uint32_t const remaining = this->subtract_reference();
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
std::experimental::coroutine_handle<Derived>::from_promise(*static_cast<Derived*>(this)).destroy();
|
||||
}
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
void Completed(CompletedHandler const& handler)
|
||||
{
|
||||
AsyncStatus status;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_completed_assigned)
|
||||
{
|
||||
throw hresult_illegal_delegate_assignment();
|
||||
}
|
||||
|
||||
m_completed_assigned = true;
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_completed = make_agile_delegate(handler);
|
||||
return;
|
||||
}
|
||||
|
||||
status = m_status;
|
||||
}
|
||||
|
||||
if (handler)
|
||||
{
|
||||
handler(*this, status);
|
||||
}
|
||||
}
|
||||
|
||||
CompletedHandler Completed() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
return m_completed;
|
||||
}
|
||||
|
||||
uint32_t Id() const noexcept
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
AsyncStatus Status() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
return m_status;
|
||||
}
|
||||
|
||||
hresult ErrorCode() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
rethrow_if_failed();
|
||||
return error_ok;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return to_hresult();
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel() noexcept
|
||||
{
|
||||
winrt::delegate<> cancel;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_status = AsyncStatus::Canceled;
|
||||
m_exception = std::make_exception_ptr(hresult_canceled());
|
||||
cancel = std::move(m_cancel);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancel)
|
||||
{
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void Close() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
auto GetResults()
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Completed)
|
||||
{
|
||||
return static_cast<Derived*>(this)->get_return_value();
|
||||
}
|
||||
|
||||
rethrow_if_failed();
|
||||
WINRT_ASSERT(m_status == AsyncStatus::Started);
|
||||
throw hresult_illegal_method_call();
|
||||
}
|
||||
|
||||
AsyncInterface get_return_object() const noexcept
|
||||
{
|
||||
return*this;
|
||||
}
|
||||
|
||||
void get_return_value() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void set_completed() noexcept
|
||||
{
|
||||
CompletedHandler handler;
|
||||
AsyncStatus status;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_status = AsyncStatus::Completed;
|
||||
}
|
||||
|
||||
handler = std::move(this->m_completed);
|
||||
status = this->m_status;
|
||||
}
|
||||
|
||||
if (handler)
|
||||
{
|
||||
handler(*this, status);
|
||||
}
|
||||
}
|
||||
|
||||
std::experimental::suspend_never initial_suspend() const noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
auto final_suspend() noexcept
|
||||
{
|
||||
struct awaiter
|
||||
{
|
||||
promise_base* promise;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
promise->set_completed();
|
||||
uint32_t const remaining = promise->subtract_reference();
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
return remaining > 0;
|
||||
}
|
||||
};
|
||||
|
||||
return awaiter{ this };
|
||||
}
|
||||
|
||||
void unhandled_exception() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
WINRT_ASSERT(m_status == AsyncStatus::Started || m_status == AsyncStatus::Canceled);
|
||||
m_exception = std::current_exception();
|
||||
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(m_exception);
|
||||
}
|
||||
catch (hresult_canceled const&)
|
||||
{
|
||||
m_status = AsyncStatus::Canceled;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_status = AsyncStatus::Error;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Expression>
|
||||
Expression&& await_transform(Expression&& expression)
|
||||
{
|
||||
if (Status() == AsyncStatus::Canceled)
|
||||
{
|
||||
throw winrt::hresult_canceled();
|
||||
}
|
||||
|
||||
return std::forward<Expression>(expression);
|
||||
}
|
||||
|
||||
cancellation_token<Derived> await_transform(get_cancellation_token_t) noexcept
|
||||
{
|
||||
return{ static_cast<Derived*>(this) };
|
||||
}
|
||||
|
||||
progress_token<Derived, TProgress> await_transform(get_progress_token_t) noexcept
|
||||
{
|
||||
return{ static_cast<Derived*>(this) };
|
||||
}
|
||||
|
||||
void cancellation_callback(winrt::delegate<>&& cancel) noexcept
|
||||
{
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status != AsyncStatus::Canceled)
|
||||
{
|
||||
m_cancel = std::move(cancel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cancel();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void rethrow_if_failed() const
|
||||
{
|
||||
if (m_status == AsyncStatus::Error || m_status == AsyncStatus::Canceled)
|
||||
{
|
||||
std::rethrow_exception(m_exception);
|
||||
}
|
||||
}
|
||||
|
||||
std::exception_ptr m_exception{};
|
||||
slim_mutex m_lock;
|
||||
CompletedHandler m_completed;
|
||||
winrt::delegate<> m_cancel;
|
||||
AsyncStatus m_status{ AsyncStatus::Started };
|
||||
bool m_completed_assigned{ false };
|
||||
};
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
|
||||
namespace winrt::impl
|
||||
{
|
||||
template <typename Async>
|
||||
struct await_adapter
|
||||
{
|
||||
Async const& async;
|
||||
|
||||
bool await_ready() const
|
||||
{
|
||||
return async.Status() == Windows::Foundation::AsyncStatus::Completed;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
auto context = capture<IContextCallback>(WINRT_CoGetObjectContext);
|
||||
|
||||
async.Completed([handle, context = std::move(context)](auto const&, Windows::Foundation::AsyncStatus)
|
||||
{
|
||||
com_callback_args args{};
|
||||
args.data = handle.address();
|
||||
|
||||
auto callback = [](com_callback_args* args) noexcept -> int32_t
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(args->data)();
|
||||
return error_ok;
|
||||
};
|
||||
|
||||
check_hresult(context->ContextCallback(callback, &args, guid_of<impl::ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
|
||||
});
|
||||
}
|
||||
|
||||
auto await_resume() const
|
||||
{
|
||||
return async.GetResults();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
|
||||
namespace winrt::Windows::Foundation
|
||||
{
|
||||
inline impl::await_adapter<IAsyncAction> operator co_await(IAsyncAction const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TProgress>
|
||||
impl::await_adapter<IAsyncActionWithProgress<TProgress>> operator co_await(IAsyncActionWithProgress<TProgress> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TResult>
|
||||
impl::await_adapter<IAsyncOperation<TResult>> operator co_await(IAsyncOperation<TResult> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
|
||||
template <typename TResult, typename TProgress>
|
||||
impl::await_adapter<IAsyncOperationWithProgress<TResult, TProgress>> operator co_await(IAsyncOperationWithProgress<TResult, TProgress> const& async)
|
||||
{
|
||||
return{ async };
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace winrt
|
||||
{
|
||||
struct get_progress_token_t {};
|
||||
|
||||
inline get_progress_token_t get_progress_token() noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
struct get_cancellation_token_t {};
|
||||
|
||||
inline get_cancellation_token_t get_cancellation_token() noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
}
|
||||
|
||||
namespace winrt::impl
|
||||
{
|
||||
template <typename Promise>
|
||||
struct cancellation_token
|
||||
{
|
||||
cancellation_token(Promise* promise) noexcept : m_promise(promise)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
cancellation_token<Promise> await_resume() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator()() const noexcept
|
||||
{
|
||||
return m_promise->Status() == Windows::Foundation::AsyncStatus::Canceled;
|
||||
}
|
||||
|
||||
void callback(winrt::delegate<>&& cancel) noexcept
|
||||
{
|
||||
m_promise->cancellation_callback(std::move(cancel));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Promise* m_promise;
|
||||
};
|
||||
|
||||
template <typename Promise, typename Progress>
|
||||
struct progress_token
|
||||
{
|
||||
progress_token(Promise* promise) noexcept :
|
||||
m_promise(promise)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
progress_token<Promise, Progress> await_resume() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()(Progress const& result)
|
||||
{
|
||||
m_promise->set_progress(result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Promise* m_promise;
|
||||
};
|
||||
|
||||
template <typename Derived, typename AsyncInterface, typename CompletedHandler, typename TProgress = void>
|
||||
struct promise_base : implements<Derived, AsyncInterface, Windows::Foundation::IAsyncInfo>
|
||||
{
|
||||
using AsyncStatus = Windows::Foundation::AsyncStatus;
|
||||
|
||||
unsigned long WINRT_CALL Release() noexcept
|
||||
{
|
||||
uint32_t const remaining = this->subtract_reference();
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
std::experimental::coroutine_handle<Derived>::from_promise(*static_cast<Derived*>(this)).destroy();
|
||||
}
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
void Completed(CompletedHandler const& handler)
|
||||
{
|
||||
AsyncStatus status;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_completed_assigned)
|
||||
{
|
||||
throw hresult_illegal_delegate_assignment();
|
||||
}
|
||||
|
||||
m_completed_assigned = true;
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_completed = make_agile_delegate(handler);
|
||||
return;
|
||||
}
|
||||
|
||||
status = m_status;
|
||||
}
|
||||
|
||||
if (handler)
|
||||
{
|
||||
handler(*this, status);
|
||||
}
|
||||
}
|
||||
|
||||
CompletedHandler Completed() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
return m_completed;
|
||||
}
|
||||
|
||||
uint32_t Id() const noexcept
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
AsyncStatus Status() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
return m_status;
|
||||
}
|
||||
|
||||
hresult ErrorCode() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
rethrow_if_failed();
|
||||
return error_ok;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return to_hresult();
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel() noexcept
|
||||
{
|
||||
winrt::delegate<> cancel;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_status = AsyncStatus::Canceled;
|
||||
m_exception = std::make_exception_ptr(hresult_canceled());
|
||||
cancel = std::move(m_cancel);
|
||||
}
|
||||
}
|
||||
|
||||
if (cancel)
|
||||
{
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void Close() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
auto GetResults()
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Completed)
|
||||
{
|
||||
return static_cast<Derived*>(this)->get_return_value();
|
||||
}
|
||||
|
||||
rethrow_if_failed();
|
||||
WINRT_ASSERT(m_status == AsyncStatus::Started);
|
||||
throw hresult_illegal_method_call();
|
||||
}
|
||||
|
||||
AsyncInterface get_return_object() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
void get_return_value() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void set_completed() noexcept
|
||||
{
|
||||
CompletedHandler handler;
|
||||
AsyncStatus status;
|
||||
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status == AsyncStatus::Started)
|
||||
{
|
||||
m_status = AsyncStatus::Completed;
|
||||
}
|
||||
|
||||
handler = std::move(this->m_completed);
|
||||
status = this->m_status;
|
||||
}
|
||||
|
||||
if (handler)
|
||||
{
|
||||
handler(*this, status);
|
||||
}
|
||||
}
|
||||
|
||||
std::experimental::suspend_never initial_suspend() const noexcept
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
auto final_suspend() noexcept
|
||||
{
|
||||
struct awaiter
|
||||
{
|
||||
promise_base* promise;
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
bool await_suspend(std::experimental::coroutine_handle<>) const noexcept
|
||||
{
|
||||
promise->set_completed();
|
||||
uint32_t const remaining = promise->subtract_reference();
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
return remaining > 0;
|
||||
}
|
||||
};
|
||||
|
||||
return awaiter{ this };
|
||||
}
|
||||
|
||||
void unhandled_exception() noexcept
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
WINRT_ASSERT(m_status == AsyncStatus::Started || m_status == AsyncStatus::Canceled);
|
||||
m_exception = std::current_exception();
|
||||
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(m_exception);
|
||||
}
|
||||
catch (hresult_canceled const&)
|
||||
{
|
||||
m_status = AsyncStatus::Canceled;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_status = AsyncStatus::Error;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Expression>
|
||||
Expression&& await_transform(Expression&& expression)
|
||||
{
|
||||
if (Status() == AsyncStatus::Canceled)
|
||||
{
|
||||
throw winrt::hresult_canceled();
|
||||
}
|
||||
|
||||
return std::forward<Expression>(expression);
|
||||
}
|
||||
|
||||
cancellation_token<Derived> await_transform(get_cancellation_token_t) noexcept
|
||||
{
|
||||
return{ static_cast<Derived*>(this) };
|
||||
}
|
||||
|
||||
progress_token<Derived, TProgress> await_transform(get_progress_token_t) noexcept
|
||||
{
|
||||
return{ static_cast<Derived*>(this) };
|
||||
}
|
||||
|
||||
void cancellation_callback(winrt::delegate<>&& cancel) noexcept
|
||||
{
|
||||
{
|
||||
slim_lock_guard const guard(m_lock);
|
||||
|
||||
if (m_status != AsyncStatus::Canceled)
|
||||
{
|
||||
m_cancel = std::move(cancel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cancel();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void rethrow_if_failed() const
|
||||
{
|
||||
if (m_status == AsyncStatus::Error || m_status == AsyncStatus::Canceled)
|
||||
{
|
||||
std::rethrow_exception(m_exception);
|
||||
}
|
||||
}
|
||||
|
||||
std::exception_ptr m_exception{};
|
||||
slim_mutex m_lock;
|
||||
CompletedHandler m_completed;
|
||||
winrt::delegate<> m_cancel;
|
||||
AsyncStatus m_status{ AsyncStatus::Started };
|
||||
bool m_completed_assigned{ false };
|
||||
};
|
||||
}
|
|
@ -0,0 +1,314 @@
|
|||
|
||||
namespace winrt
|
||||
{
|
||||
[[nodiscard]] inline auto resume_background() noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
if (!WINRT_TrySubmitThreadpoolCallback(callback, handle.address(), nullptr))
|
||||
{
|
||||
throw_last_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(context)();
|
||||
}
|
||||
};
|
||||
|
||||
return awaitable{};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] auto resume_background(T const& context) noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(T const& context) : m_context(context)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> resume)
|
||||
{
|
||||
m_resume = resume;
|
||||
|
||||
if (!WINRT_TrySubmitThreadpoolCallback(callback, this, nullptr))
|
||||
{
|
||||
throw_last_error();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context) noexcept
|
||||
{
|
||||
auto that = static_cast<awaitable*>(context);
|
||||
auto guard = that->m_context();
|
||||
that->m_resume();
|
||||
}
|
||||
|
||||
T const& m_context;
|
||||
std::experimental::coroutine_handle<> m_resume{ nullptr };
|
||||
};
|
||||
|
||||
return awaitable{ context };
|
||||
}
|
||||
|
||||
struct apartment_context
|
||||
{
|
||||
apartment_context()
|
||||
{
|
||||
m_context.capture(WINRT_CoGetObjectContext);
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
impl::com_callback_args args{};
|
||||
args.data = handle.address();
|
||||
check_hresult(m_context->ContextCallback(callback, &args, guid_of<impl::ICallbackWithNoReentrancyToApplicationSTA>(), 5, nullptr));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static int32_t WINRT_CALL callback(impl::com_callback_args* args) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(args->data)();
|
||||
return impl::error_ok;
|
||||
}
|
||||
|
||||
com_ptr<impl::IContextCallback> m_context;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline auto resume_after(Windows::Foundation::TimeSpan duration) noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
explicit awaitable(Windows::Foundation::TimeSpan duration) noexcept :
|
||||
m_duration(duration)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return m_duration.count() <= 0;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle)
|
||||
{
|
||||
m_timer.attach(check_pointer(WINRT_CreateThreadpoolTimer(callback, handle.address(), nullptr)));
|
||||
int64_t relative_count = -m_duration.count();
|
||||
WINRT_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0);
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context, void*) noexcept
|
||||
{
|
||||
std::experimental::coroutine_handle<>::from_address(context)();
|
||||
}
|
||||
|
||||
struct timer_traits
|
||||
{
|
||||
using type = impl::ptp_timer;
|
||||
|
||||
static void close(type value) noexcept
|
||||
{
|
||||
WINRT_CloseThreadpoolTimer(value);
|
||||
}
|
||||
|
||||
static constexpr type invalid() noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
handle_type<timer_traits> m_timer;
|
||||
Windows::Foundation::TimeSpan m_duration;
|
||||
};
|
||||
|
||||
return awaitable{ duration };
|
||||
}
|
||||
|
||||
inline auto operator co_await(Windows::Foundation::TimeSpan duration)
|
||||
{
|
||||
return resume_after(duration);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(void* handle, Windows::Foundation::TimeSpan timeout) noexcept :
|
||||
m_timeout(timeout),
|
||||
m_handle(handle)
|
||||
{}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return WINRT_WaitForSingleObject(m_handle, 0) == 0;
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> resume)
|
||||
{
|
||||
m_resume = resume;
|
||||
m_wait.attach(check_pointer(WINRT_CreateThreadpoolWait(callback, this, nullptr)));
|
||||
int64_t relative_count = -m_timeout.count();
|
||||
int64_t* file_time = relative_count != 0 ? &relative_count : nullptr;
|
||||
WINRT_SetThreadpoolWait(m_wait.get(), m_handle, file_time);
|
||||
}
|
||||
|
||||
bool await_resume() const noexcept
|
||||
{
|
||||
return m_result == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static void WINRT_CALL callback(void*, void* context, void*, uint32_t result) noexcept
|
||||
{
|
||||
auto that = static_cast<awaitable*>(context);
|
||||
that->m_result = result;
|
||||
that->m_resume();
|
||||
}
|
||||
|
||||
struct wait_traits
|
||||
{
|
||||
using type = impl::ptp_wait;
|
||||
|
||||
static void close(type value) noexcept
|
||||
{
|
||||
WINRT_CloseThreadpoolWait(value);
|
||||
}
|
||||
|
||||
static constexpr type invalid() noexcept
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
handle_type<wait_traits> m_wait;
|
||||
Windows::Foundation::TimeSpan m_timeout;
|
||||
void* m_handle;
|
||||
uint32_t m_result{};
|
||||
std::experimental::coroutine_handle<> m_resume{ nullptr };
|
||||
};
|
||||
|
||||
return awaitable{ handle, timeout };
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto resume_foreground(
|
||||
Windows::UI::Core::CoreDispatcher const& dispatcher,
|
||||
Windows::UI::Core::CoreDispatcherPriority const priority = Windows::UI::Core::CoreDispatcherPriority::Normal) noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(Windows::UI::Core::CoreDispatcher const& dispatcher, Windows::UI::Core::CoreDispatcherPriority const priority) noexcept :
|
||||
m_dispatcher(dispatcher),
|
||||
m_priority(priority)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const
|
||||
{
|
||||
return m_dispatcher.HasThreadAccess();
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
m_dispatcher.RunAsync(m_priority, [handle]
|
||||
{
|
||||
handle();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Windows::UI::Core::CoreDispatcher const& m_dispatcher;
|
||||
Windows::UI::Core::CoreDispatcherPriority const m_priority;
|
||||
};
|
||||
|
||||
return awaitable{ dispatcher, priority };
|
||||
};
|
||||
|
||||
[[nodiscard]] inline auto resume_foreground(
|
||||
Windows::System::DispatcherQueue const& dispatcher,
|
||||
Windows::System::DispatcherQueuePriority const priority = Windows::System::DispatcherQueuePriority::Normal) noexcept
|
||||
{
|
||||
struct awaitable
|
||||
{
|
||||
awaitable(Windows::System::DispatcherQueue const& dispatcher, Windows::System::DispatcherQueuePriority const priority) noexcept :
|
||||
m_dispatcher(dispatcher),
|
||||
m_priority(priority)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool await_resume() const noexcept
|
||||
{
|
||||
return m_queued;
|
||||
}
|
||||
|
||||
bool await_suspend(std::experimental::coroutine_handle<> handle)
|
||||
{
|
||||
m_queued = m_dispatcher.TryEnqueue(m_priority, [handle]
|
||||
{
|
||||
handle();
|
||||
});
|
||||
|
||||
return m_queued;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Windows::System::DispatcherQueue const& m_dispatcher;
|
||||
Windows::System::DispatcherQueuePriority const m_priority;
|
||||
bool m_queued{};
|
||||
};
|
||||
|
||||
return awaitable{ dispatcher, priority };
|
||||
};
|
||||
}
|
|
@ -20,7 +20,6 @@
|
|||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <experimental/coroutine>
|
||||
|
||||
#if __has_include(<WindowsNumerics.impl.h>)
|
||||
#define WINRT_NUMERICS
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
namespace winrt
|
||||
{
|
||||
struct resume_foreground
|
||||
{
|
||||
explicit resume_foreground(Windows::UI::Core::CoreDispatcher&& dispatcher, Windows::UI::Core::CoreDispatcherPriority const priority = Windows::UI::Core::CoreDispatcherPriority::Normal) :
|
||||
m_dispatcher(std::move(dispatcher)),
|
||||
m_priority(priority)
|
||||
{
|
||||
}
|
||||
|
||||
explicit resume_foreground(Windows::UI::Core::CoreDispatcher const& dispatcher, Windows::UI::Core::CoreDispatcherPriority const priority = Windows::UI::Core::CoreDispatcherPriority::Normal) :
|
||||
m_dispatcher(dispatcher),
|
||||
m_priority(priority)
|
||||
{
|
||||
}
|
||||
|
||||
bool await_ready() const
|
||||
{
|
||||
return m_dispatcher.HasThreadAccess();
|
||||
}
|
||||
|
||||
void await_resume() const noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void await_suspend(std::experimental::coroutine_handle<> handle) const
|
||||
{
|
||||
m_dispatcher.RunAsync(m_priority, [handle]
|
||||
{
|
||||
handle();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Windows::UI::Core::CoreDispatcher const m_dispatcher;
|
||||
Windows::UI::Core::CoreDispatcherPriority const m_priority;
|
||||
};
|
||||
}
|
Загрузка…
Ссылка в новой задаче