File unix.h

File List > coroutine > unix.h

Go to the documentation of this file.

#ifndef COROUTINE_SYSTEM_WRAPPER_H
#define COROUTINE_SYSTEM_WRAPPER_H
#if !(defined(unix) || defined(__APPLE__) || defined(__FreeBSD__))
#error "expect UNIX platform for this file"
#endif
#include <sys/event.h> // for BSD kqueue

#include <gsl/gsl>

#include <coroutine/return.h>

namespace coro {

class kqueue_owner final {
    int64_t kqfd;

  public:
    kqueue_owner() noexcept(false);
    ~kqueue_owner() noexcept;
    kqueue_owner(const kqueue_owner&) = delete;
    kqueue_owner(kqueue_owner&&) = delete;
    kqueue_owner& operator=(const kqueue_owner&) = delete;
    kqueue_owner& operator=(kqueue_owner&&) = delete;

  public:
    void change(kevent64_s& req) noexcept(false);

    ptrdiff_t events(const timespec& wait_time,
                     gsl::span<kevent64_s> list) noexcept(false);

  public:
    [[nodiscard]] auto submit(kevent64_s& req) noexcept {
        class awaiter final : public suspend_always {
            kqueue_owner& kq;
            kevent64_s& req;

          public:
            constexpr awaiter(kqueue_owner& _kq, kevent64_s& _req)
                : kq{_kq}, req{_req} {
            }

          public:
            void await_suspend(coroutine_handle<void> coro) noexcept(false) {
                if (req.udata == 0)
                    req.udata = reinterpret_cast<uint64_t>(coro.address());
                return kq.change(req);
            }
        };
        return awaiter{*this, req};
    }
};

} // namespace coro

#endif // COROUTINE_SYSTEM_WRAPPER_H