Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable async stack support for MSVC #633

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmake/unifex_env.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ endif()

if (UNIFEX_CXX_COMPILER_MSVC)
# warning level 3 and all warnings as errors
add_compile_options(/W3 /WX)
add_compile_options(/W3 /WX /bigobj)
else()
# lots of warnings and all warnings as errors
add_compile_options(-Wall -Wextra -pedantic -Werror)
Expand Down
12 changes: 9 additions & 3 deletions examples/fp_delegation.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
Expand All @@ -13,6 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(_MSC_VER) && !defined(__clang__)
// async stacks break this file when building with MSVC; we can probably fix it
// by switching the implementation to use unifex::variant_sender, but that's a
// post-CppCon problem
# define UNIFEX_NO_ASYNC_STACKS 1
#endif

#include <unifex/for_each.hpp>
#include <unifex/manual_event_loop.hpp>
Expand Down Expand Up @@ -135,15 +141,15 @@ class delegating_sender {
auto local_op = [&receiver, context = context_]() mutable {
return LC{unifex::connect(
unifex::schedule(context->single_thread_context_.get_scheduler()),
(Receiver &&) receiver)};
(Receiver&&)receiver)};
};
return op{std::move(local_op), context_};
}

auto target_op = [&receiver]() mutable {
return unifex::connect(
unifex::schedule(unifex::get_scheduler(std::as_const(receiver))),
(Receiver &&) receiver);
(Receiver&&)receiver);
};

return op{std::move(target_op), context_};
Expand Down
20 changes: 11 additions & 9 deletions include/unifex/await_transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,9 @@ class _awaitable_wrapper<Awaitable>::type final {
coro::coroutine_handle<>,
_suspend_result_t<Promise>>;

template(typename Promise) //
(requires same_as<bool, suspend_result_t<Promise>>) //
bool await_suspend_impl(
coro::coroutine_handle<Promise> h, AsyncStackFrame* frame) {
template <typename Promise>
bool await_suspend_bool(
coro::coroutine_handle<Promise> h, AsyncStackFrame* frame) {
auto* root = frame->getStackRoot();

auto resumer = resume_with_stack_root(h).handle();
Expand Down Expand Up @@ -418,10 +417,9 @@ class _awaitable_wrapper<Awaitable>::type final {
}
}

template(typename Promise) //
(requires(!same_as<bool, suspend_result_t<Promise>>)) //
suspend_result_t<Promise> await_suspend_impl(
coro::coroutine_handle<Promise> h, AsyncStackFrame* frame) {
template <typename Promise>
suspend_result_t<Promise> await_suspend_impl(
coro::coroutine_handle<Promise> h, AsyncStackFrame* frame) {
auto resumer = resume_with_stack_root(h).handle();

// save for later destruction
Expand All @@ -437,7 +435,11 @@ class _awaitable_wrapper<Awaitable>::type final {
template <typename Promise>
suspend_result_t<Promise> await_suspend(coro::coroutine_handle<Promise> h) {
if (auto* frame = get_async_stack_frame(h.promise())) {
return await_suspend_impl(h, frame);
if constexpr (same_as<bool, suspend_result_t<Promise>>) {
return await_suspend_bool(h, frame);
} else {
return await_suspend_impl(h, frame);
}
}

using awaiter_suspend_result_t = decltype(awaiter_.await_suspend(h));
Expand Down
31 changes: 27 additions & 4 deletions include/unifex/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,36 @@
#if !defined(UNIFEX_NO_ASYNC_STACKS)
// default:
// - release builds do not have async stacks
// - Windows builds do not have async stacks
//
// adding async stacks adds non-trivial binary size at the moment, and I can't
// figure out how to make all the relevant Windows builds succeed
# if defined(NDEBUG) || defined(_MSC_VER)
// adding async stacks adds non-trivial binary size at the moment
# if defined(NDEBUG)
# define UNIFEX_NO_ASYNC_STACKS 1
# else
# define UNIFEX_NO_ASYNC_STACKS 0
# endif
#elif UNIFEX_NO_ASYNC_STACKS
// make sure the truthy value is 1
# undef UNIFEX_NO_ASYNC_STACKS
# define UNIFEX_NO_ASYNC_STACKS 1
#else
// make sure the falsey value is 0
# undef UNIFEX_NO_ASYNC_STACKS
# define UNIFEX_NO_ASYNC_STACKS 0
#endif // !defined(UNIFEX_NO_ASYNC_STACKS)

#if UNIFEX_HAS_BUILTIN(__builtin_return_address)
# define UNIFEX_RETURN_ADDRESS __builtin_return_address(0)
#elif defined(_MSC_VER)
# define UNIFEX_RETURN_ADDRESS _ReturnAddress()
#else
# define UNIFEX_RETURN_ADDRESS nullptr
#endif

#if UNIFEX_HAS_BUILTIN(__builtin_frame_address)
# define UNIFEX_FRAME_ADDRESS __builtin_frame_address(0)
#elif defined(_MSC_VER)
// not sure, yet, that this is right, but it's where we're starting
# define UNIFEX_FRAME_ADDRESS _AddressOfReturnAddress()
#else
# define UNIFEX_FRAME_ADDRESS nullptr
#endif
18 changes: 7 additions & 11 deletions include/unifex/tracing/async_stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include <cassert>
#include <cstdint>

#if defined(_MSC_VER)
// needed for _ReturnAddress() and _AddressOfReturnAddress()
#include <intrin.h>
#endif

#include <unifex/detail/prologue.hpp>

namespace unifex {
Expand Down Expand Up @@ -273,13 +278,8 @@ struct instruction_ptr final {
// Generally a function that uses this macro should be declared FOLLY_NOINLINE
// to prevent this returning surprising results in cases where the function
// is inlined.
#if UNIFEX_HAS_BUILTIN(__builtin_return_address)
static constexpr instruction_ptr
read_return_address(void* p = __builtin_return_address(0)) noexcept {
#else
static constexpr instruction_ptr
read_return_address(void* p = nullptr) noexcept {
#endif
read_return_address(void* p = UNIFEX_RETURN_ADDRESS) noexcept {
return instruction_ptr{p};
}

Expand Down Expand Up @@ -311,12 +311,8 @@ struct frame_ptr {
// Generally a function that uses this macro should be declared FOLLY_NOINLINE
// to prevent this returning surprising results in cases where the function
// is inlined.
#if UNIFEX_HAS_BUILTIN(__builtin_frame_address)
static constexpr frame_ptr
read_frame_pointer(void* p = __builtin_frame_address(0)) noexcept {
#else
static constexpr frame_ptr read_frame_pointer(void* p = nullptr) noexcept {
#endif
read_frame_pointer(void* p = UNIFEX_FRAME_ADDRESS) noexcept {
return frame_ptr{p};
}

Expand Down
Loading