Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-11-15 09:02:48

0001 //
0002 // detail/io_uring_service.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IO_URING_SERVICE_HPP
0012 #define BOOST_ASIO_DETAIL_IO_URING_SERVICE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_HAS_IO_URING)
0021 
0022 #include <liburing.h>
0023 #include <boost/asio/detail/atomic_count.hpp>
0024 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0025 #include <boost/asio/detail/conditionally_enabled_mutex.hpp>
0026 #include <boost/asio/detail/io_uring_operation.hpp>
0027 #include <boost/asio/detail/limits.hpp>
0028 #include <boost/asio/detail/object_pool.hpp>
0029 #include <boost/asio/detail/op_queue.hpp>
0030 #include <boost/asio/detail/reactor.hpp>
0031 #include <boost/asio/detail/scheduler_task.hpp>
0032 #include <boost/asio/detail/timer_queue_base.hpp>
0033 #include <boost/asio/detail/timer_queue_set.hpp>
0034 #include <boost/asio/detail/wait_op.hpp>
0035 #include <boost/asio/execution_context.hpp>
0036 
0037 #include <boost/asio/detail/push_options.hpp>
0038 
0039 namespace boost {
0040 namespace asio {
0041 namespace detail {
0042 
0043 class io_uring_service
0044   : public execution_context_service_base<io_uring_service>,
0045     public scheduler_task
0046 {
0047 private:
0048   // The mutex type used by this reactor.
0049   typedef conditionally_enabled_mutex mutex;
0050 
0051 public:
0052   enum op_types { read_op = 0, write_op = 1, except_op = 2, max_ops = 3 };
0053 
0054   class io_object;
0055 
0056   // An I/O queue stores operations that must run serially.
0057   class io_queue : operation
0058   {
0059     friend class io_uring_service;
0060 
0061     io_object* io_object_;
0062     op_queue<io_uring_operation> op_queue_;
0063     bool cancel_requested_;
0064 
0065     BOOST_ASIO_DECL io_queue();
0066     void set_result(int r) { task_result_ = static_cast<unsigned>(r); }
0067     BOOST_ASIO_DECL operation* perform_io(int result);
0068     BOOST_ASIO_DECL static void do_complete(void* owner, operation* base,
0069         const boost::system::error_code& ec, std::size_t bytes_transferred);
0070   };
0071 
0072   // Per I/O object state.
0073   class io_object
0074   {
0075     friend class io_uring_service;
0076     friend class object_pool_access;
0077 
0078     io_object* next_;
0079     io_object* prev_;
0080 
0081     mutex mutex_;
0082     io_uring_service* service_;
0083     io_queue queues_[max_ops];
0084     bool shutdown_;
0085 
0086     BOOST_ASIO_DECL io_object(bool locking);
0087   };
0088 
0089   // Per I/O object data.
0090   typedef io_object* per_io_object_data;
0091 
0092   // Constructor.
0093   BOOST_ASIO_DECL io_uring_service(boost::asio::execution_context& ctx);
0094 
0095   // Destructor.
0096   BOOST_ASIO_DECL ~io_uring_service();
0097 
0098   // Destroy all user-defined handler objects owned by the service.
0099   BOOST_ASIO_DECL void shutdown();
0100 
0101   // Recreate internal state following a fork.
0102   BOOST_ASIO_DECL void notify_fork(
0103       boost::asio::execution_context::fork_event fork_ev);
0104 
0105   // Initialise the task.
0106   BOOST_ASIO_DECL void init_task();
0107 
0108   // Register an I/O object with io_uring.
0109   BOOST_ASIO_DECL void register_io_object(io_object*& io_obj);
0110 
0111   // Register an internal I/O object with io_uring.
0112   BOOST_ASIO_DECL void register_internal_io_object(
0113       io_object*& io_obj, int op_type, io_uring_operation* op);
0114 
0115   // Register buffers with io_uring.
0116   BOOST_ASIO_DECL void register_buffers(const ::iovec* v, unsigned n);
0117 
0118   // Unregister buffers from io_uring.
0119   BOOST_ASIO_DECL void unregister_buffers();
0120 
0121   // Post an operation for immediate completion.
0122   void post_immediate_completion(operation* op, bool is_continuation);
0123 
0124   // Start a new operation. The operation will be prepared and submitted to the
0125   // io_uring when it is at the head of its I/O operation queue.
0126   BOOST_ASIO_DECL void start_op(int op_type, per_io_object_data& io_obj,
0127       io_uring_operation* op, bool is_continuation);
0128 
0129   // Cancel all operations associated with the given I/O object. The handlers
0130   // associated with the I/O object will be invoked with the operation_aborted
0131   // error.
0132   BOOST_ASIO_DECL void cancel_ops(per_io_object_data& io_obj);
0133 
0134   // Cancel all operations associated with the given I/O object and key. The
0135   // handlers associated with the object and key will be invoked with the
0136   // operation_aborted error.
0137   BOOST_ASIO_DECL void cancel_ops_by_key(per_io_object_data& io_obj,
0138       int op_type, void* cancellation_key);
0139 
0140   // Cancel any operations that are running against the I/O object and remove
0141   // its registration from the service. The service resources associated with
0142   // the I/O object must be released by calling cleanup_io_object.
0143   BOOST_ASIO_DECL void deregister_io_object(per_io_object_data& io_obj);
0144 
0145   // Perform any post-deregistration cleanup tasks associated with the I/O
0146   // object.
0147   BOOST_ASIO_DECL void cleanup_io_object(per_io_object_data& io_obj);
0148 
0149   // Add a new timer queue to the reactor.
0150   template <typename Time_Traits>
0151   void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
0152 
0153   // Remove a timer queue from the reactor.
0154   template <typename Time_Traits>
0155   void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
0156 
0157   // Schedule a new operation in the given timer queue to expire at the
0158   // specified absolute time.
0159   template <typename Time_Traits>
0160   void schedule_timer(timer_queue<Time_Traits>& queue,
0161       const typename Time_Traits::time_type& time,
0162       typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
0163 
0164   // Cancel the timer operations associated with the given token. Returns the
0165   // number of operations that have been posted or dispatched.
0166   template <typename Time_Traits>
0167   std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
0168       typename timer_queue<Time_Traits>::per_timer_data& timer,
0169       std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
0170 
0171   // Cancel the timer operations associated with the given key.
0172   template <typename Time_Traits>
0173   void cancel_timer_by_key(timer_queue<Time_Traits>& queue,
0174       typename timer_queue<Time_Traits>::per_timer_data* timer,
0175       void* cancellation_key);
0176 
0177   // Move the timer operations associated with the given timer.
0178   template <typename Time_Traits>
0179   void move_timer(timer_queue<Time_Traits>& queue,
0180       typename timer_queue<Time_Traits>::per_timer_data& target,
0181       typename timer_queue<Time_Traits>::per_timer_data& source);
0182 
0183   // Wait on io_uring once until interrupted or events are ready to be
0184   // dispatched.
0185   BOOST_ASIO_DECL void run(long usec, op_queue<operation>& ops);
0186 
0187   // Interrupt the io_uring wait.
0188   BOOST_ASIO_DECL void interrupt();
0189 
0190 private:
0191   // The hint to pass to io_uring_queue_init to size its data structures.
0192   enum { ring_size = 16384 };
0193 
0194   // The number of operations to submit in a batch.
0195   enum { submit_batch_size = 128 };
0196 
0197   // The number of operations to complete in a batch.
0198   enum { complete_batch_size = 128 };
0199 
0200   // The type used for processing eventfd readiness notifications.
0201   class event_fd_read_op;
0202 
0203   // Initialise the ring.
0204   BOOST_ASIO_DECL void init_ring();
0205 
0206   // Register the eventfd descriptor for readiness notifications.
0207   BOOST_ASIO_DECL void register_with_reactor();
0208 
0209   // Allocate a new I/O object.
0210   BOOST_ASIO_DECL io_object* allocate_io_object();
0211 
0212   // Free an existing I/O object.
0213   BOOST_ASIO_DECL void free_io_object(io_object* s);
0214 
0215   // Helper function to cancel all operations associated with the given I/O
0216   // object. This function must be called while the I/O object's mutex is held.
0217   // Returns true if there are operations for which cancellation is pending.
0218   BOOST_ASIO_DECL bool do_cancel_ops(
0219       per_io_object_data& io_obj, op_queue<operation>& ops);
0220 
0221   // Helper function to add a new timer queue.
0222   BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
0223 
0224   // Helper function to remove a timer queue.
0225   BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
0226 
0227   // Called to recalculate and update the timeout.
0228   BOOST_ASIO_DECL void update_timeout();
0229 
0230   // Get the current timeout value.
0231   BOOST_ASIO_DECL __kernel_timespec get_timeout() const;
0232 
0233   // Get a new submission queue entry, flushing the queue if necessary.
0234   BOOST_ASIO_DECL ::io_uring_sqe* get_sqe();
0235 
0236   // Submit pending submission queue entries.
0237   BOOST_ASIO_DECL void submit_sqes();
0238 
0239   // Post an operation to submit the pending submission queue entries.
0240   BOOST_ASIO_DECL void post_submit_sqes_op(mutex::scoped_lock& lock);
0241 
0242   // Push an operation to submit the pending submission queue entries.
0243   BOOST_ASIO_DECL void push_submit_sqes_op(op_queue<operation>& ops);
0244 
0245   // Helper operation to submit pending submission queue entries.
0246   class submit_sqes_op : operation
0247   {
0248     friend class io_uring_service;
0249 
0250     io_uring_service* service_;
0251 
0252     BOOST_ASIO_DECL submit_sqes_op(io_uring_service* s);
0253     BOOST_ASIO_DECL static void do_complete(void* owner, operation* base,
0254         const boost::system::error_code& ec, std::size_t bytes_transferred);
0255   };
0256 
0257   // The scheduler implementation used to post completions.
0258   scheduler& scheduler_;
0259 
0260   // Mutex to protect access to internal data.
0261   mutex mutex_;
0262 
0263   // The ring.
0264   ::io_uring ring_;
0265 
0266   // The count of unfinished work.
0267   atomic_count outstanding_work_;
0268 
0269   // The operation used to submit the pending submission queue entries.
0270   submit_sqes_op submit_sqes_op_;
0271 
0272   // The number of pending submission queue entries_.
0273   int pending_sqes_;
0274 
0275   // Whether there is a pending submission operation.
0276   bool pending_submit_sqes_op_;
0277 
0278   // Whether the service has been shut down.
0279   bool shutdown_;
0280 
0281   // The timer queues.
0282   timer_queue_set timer_queues_;
0283 
0284   // The timespec for the pending timeout operation. Must remain valid while the
0285   // operation is outstanding.
0286   __kernel_timespec timeout_;
0287 
0288   // Mutex to protect access to the registered I/O objects.
0289   mutex registration_mutex_;
0290 
0291   // Keep track of all registered I/O objects.
0292   object_pool<io_object> registered_io_objects_;
0293 
0294   // Helper class to do post-perform_io cleanup.
0295   struct perform_io_cleanup_on_block_exit;
0296   friend struct perform_io_cleanup_on_block_exit;
0297 
0298   // The reactor used to register for eventfd readiness.
0299   reactor& reactor_;
0300 
0301   // The per-descriptor reactor data used for the eventfd.
0302   reactor::per_descriptor_data reactor_data_;
0303 
0304   // The eventfd descriptor used to wait for readiness.
0305   int event_fd_;
0306 };
0307 
0308 } // namespace detail
0309 } // namespace asio
0310 } // namespace boost
0311 
0312 #include <boost/asio/detail/pop_options.hpp>
0313 
0314 #include <boost/asio/detail/impl/io_uring_service.hpp>
0315 #if defined(BOOST_ASIO_HEADER_ONLY)
0316 # include <boost/asio/detail/impl/io_uring_service.ipp>
0317 #endif // defined(BOOST_ASIO_HEADER_ONLY)
0318 
0319 #endif // defined(BOOST_ASIO_HAS_IO_URING)
0320 
0321 #endif // BOOST_ASIO_DETAIL_IO_URING_SERVICE_HPP