File windows.h

File List > coroutine > windows.h

Go to the documentation of this file.

#pragma once
#ifndef COROUTINE_SYSTEM_WRAPPER_H
#define COROUTINE_SYSTEM_WRAPPER_H
#if __has_include(<Windows.h>)
#include <Windows.h>
#else
#error "expect Windows platform for this file"
#endif
#include <system_error>

#include <coroutine/return.h>

namespace coro {

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_GAMES)

class set_or_cancel final {
    HANDLE hobject;

  public:
    explicit set_or_cancel(HANDLE target) noexcept(false);
    ~set_or_cancel() noexcept = default;
    set_or_cancel(const set_or_cancel&) = delete;
    set_or_cancel(set_or_cancel&&) = delete;
    set_or_cancel& operator=(const set_or_cancel&) = delete;
    set_or_cancel& operator=(set_or_cancel&&) = delete;

  private:
    void suspend(coroutine_handle<void>) noexcept(false);

  public:
    uint32_t unregister() noexcept;

    constexpr bool await_ready() const noexcept {
        return false;
    }
    void await_suspend(coroutine_handle<void> coro) noexcept(false) {
        return suspend(coro);
    }
    uint32_t await_resume() noexcept {
        return unregister();
    }
};
#endif // WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_GAMES

class continue_on_thread_pool final {
    static void __stdcall resume_on_thread_pool(PTP_CALLBACK_INSTANCE, PVOID,
                                                PTP_WORK);
    uint32_t create_and_submit_work(coroutine_handle<void>) noexcept;

  public:
    constexpr bool await_ready() const noexcept {
        return false;
    }
    constexpr void await_resume() noexcept {
        // nothing to do for this implementation
    }

    void await_suspend(coroutine_handle<void> coro) noexcept(false) {
        if (const auto ec = create_and_submit_work(coro))
            throw std::system_error{static_cast<int>(ec),
                                    std::system_category(),
                                    "CreateThreadpoolWork"};
    }
};

class continue_on_apc final {
    static void __stdcall resume_on_apc(ULONG_PTR);

    uint32_t queue_user_apc(coroutine_handle<void>) noexcept;

  public:
    constexpr bool await_ready() const noexcept {
        return false;
    }
    constexpr void await_resume() noexcept {
    }

    void await_suspend(coroutine_handle<void> coro) noexcept(false) {
        if (const auto ec = queue_user_apc(coro))
            throw std::system_error{static_cast<int>(ec),
                                    std::system_category(), "QueueUserAPC"};
    }

  public:
    explicit continue_on_apc(HANDLE hThread) noexcept : thread{hThread} {
    }

  private:
    HANDLE thread;
};

} // namespace coro

#endif // COROUTINE_SYSTEM_WRAPPER_H