// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_FS_AIO_H #include /// Define this to try all read requests with RWF_NOWAIT first and indicate /// EAGAIN failure with a log dwarning. On EAGAIN the request is resubmitted /// without RWF_NOWAIT if the user expected blocking behavior. //#define RB_DEBUG_FS_AIO_READ_BLOCKING /// Define to time the io_submit() system call with a syscall_usage_warning. /// This emits a warning when the kernel spent a lot of time in io_submit(). /// The resolution is very low at 10ms but it is not expensive to use. //#define RB_DEBUG_FS_AIO_SUBMIT_BLOCKING #pragma GCC visibility push(hidden) namespace ircd::fs::aio { size_t write(const fd &, const const_iovec_view &, const write_opts &); size_t read(const vector_view &); size_t read(const fd &, const const_iovec_view &, const read_opts &); size_t fsync(const fd &, const sync_opts &); } #pragma GCC visibility pop /// AIO context instance from the system. Right now this is a singleton with /// an extern instance pointer at fs::aio::context maintained by fs::aio::init. struct [[gnu::visibility("hidden")]] ircd::fs::aio::system { struct aio_context; static const int eventfd_flags; /// io_getevents vector (in) std::vector event; uint64_t ecount {0}; /// io_submit queue (out) std::vector queue; size_t qcount {0}; /// other state ctx::dock dock; size_t in_flight {0}; bool handle_set {false}; size_t handle_size {0}; std::unique_ptr handle_data; static ios::descriptor handle_descriptor; static ios::descriptor chase_descriptor; /// An eventfd which will be notified by the system; we integrate this with /// the ircd io_service core epoll() event loop. The EFD_SEMAPHORE flag is /// not used to reduce the number of triggers. The semaphore value is the /// ecount (above) which will reflect a hint for how many AIO's are done. asio::posix::stream_descriptor resfd; /// Handler to the io context we submit requests to the system with const custom_ptr head; const io_event *ring {nullptr}; size_t max_events() const; size_t max_submit() const; size_t request_count() const; // qcount + in_flight size_t request_avail() const; // max_events - request_count() // Callback stack invoked when the sigfd is notified of completed events. void handle_event(const io_event &) noexcept; void handle_events() noexcept; void handle(const boost::system::error_code &, const size_t) noexcept; void set_handle(); void dequeue_one(const std::error_code &); void dequeue_all(const std::error_code &); size_t io_submit(); size_t submit() noexcept; void chase() noexcept; bool submit(request &); bool cancel(request &); bool wait(request &); // Control panel bool wait(); bool interrupt(); system(const size_t &max_events, const size_t &max_submit); ~system() noexcept; }; struct [[gnu::visibility("internal")]] ircd::fs::aio::system::aio_context { static constexpr uint MAGIC {0xA10A10A1}; uint id; // kernel internal index number uint nr; // number of io_events uint head; uint tail; uint magic; uint compat_features; uint incompat_features; uint header_length; // size of aio_context struct io_event io_events[0]; }; // 128 bytes + ring size /// Generic request control block. struct [[gnu::visibility("hidden")]] ircd::fs::aio::request :iocb { struct read; struct write; struct fsync; ssize_t retval; ssize_t errcode; const struct opts *opts; ctx::dock *waiter; bool wait(); public: const_iovec_view iovec() const; bool completed() const; bool queued() const; size_t complete(); void submit(); bool cancel(); request(const int &fd = -1, const struct opts *const & = nullptr, ctx::dock *const & = nullptr); request(request &&) = delete; request(const request &) = delete; request &operator=(request &&) = delete; request &operator=(const request &) = delete; ~request() noexcept; }; /// Read request control block struct [[gnu::visibility("hidden")]] ircd::fs::aio::request::read :request { read(ctx::dock &, const int &fd, const read_opts &, const const_iovec_view &); read() = default; }; /// Write request control block struct [[gnu::visibility("hidden")]] ircd::fs::aio::request::write :request { write(ctx::dock &, const int &fd, const write_opts &, const const_iovec_view &); write() = default; }; /// fsync request control block struct [[gnu::visibility("hidden")]] ircd::fs::aio::request::fsync :request { fsync(ctx::dock &, const int &fd, const sync_opts &); fsync() = default; };