/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include namespace folly { class SimpleAsyncIO : public EventHandler { public: // SimpleAsyncIO is a wrapper around AsyncIO intended to hide all the details. // // Usage: just create an instance of SimpleAsyncIO and then issue IO with // pread and pwrite, no other effort required. e.g.: // // auto tmpfile = folly::File::temporary(); // folly::SimpleAsyncIO aio; // aio.pwrite( // tmpfile.fd(), // "hello world", // /*size=*/11, // /*offset=*/0, // [](int rc) { LOG(INFO) << "Write completed with result " << rc; }); // // IO is dispatched in the context of the calling thread; it may block briefly // to obtain a lock on shared resources, but will *not* block for IO // completion. If the IO queue is full (see maxRequests in Config, below), // IO fails with -EBUSY. // // IO is completed on the executor specified in the config (global CPU // executor by default). // // IO is completed by calling the callback function provided to pread/pwrite. // The single parameter to the callback is either a negative errno or the // number of bytes transferred. // // There is a "hidden" EventBase which polls for IO completion and dispatches // completion events to the executor. You may specify an existing EventBase in // the config (and you are then responsible for making sure the EventBase // instance outlives the SimpleAsyncIO instance). If you do not specify one, a // ScopedEventBaseThread instance will be created. // // Following structure defines the configuration of a SimpleAsyncIO instance, // in case you need to override the (sensible) defaults. // // Typical usage is something like: // // SimpleAsyncIO io(SimpleAsyncIO::Config() // .setMaxRequests(100) // .setMode(SimpleAsyncIO::Mode::IOURING)); // enum Mode { AIO, IOURING }; struct Config { Config() : maxRequests_(1000), completionExecutor_( getKeepAliveToken(getUnsafeMutableGlobalCPUExecutor().get())), mode_(AIO), evb_(nullptr) {} Config& setMaxRequests(size_t maxRequests) { maxRequests_ = maxRequests; return *this; } Config& setCompletionExecutor(Executor::KeepAlive<> completionExecutor) { completionExecutor_ = completionExecutor; return *this; } Config& setMode(Mode mode) { mode_ = mode; return *this; } Config& setEventBase(EventBase* evb) { evb_ = evb; return *this; } private: size_t maxRequests_; Executor::KeepAlive<> completionExecutor_; Mode mode_; EventBase* evb_; friend class SimpleAsyncIO; }; explicit SimpleAsyncIO(Config cfg = Config()); virtual ~SimpleAsyncIO() override; using SimpleAsyncIOCompletor = Function; /* Initiate an asynchronous read request. * * Parameters and return value are same as pread(2). * * Completion is indicated by an asynchronous call to the given completor * callback. The sole parameter to the callback is the result of the * operation. */ void pread( int fd, void* buf, size_t size, off_t start, SimpleAsyncIOCompletor completor); /* Initiate an asynchronous write request. * * Parameters and return value are same as pwrite(2). * * Completion is indicated by an asynchronous call to the given completor * callback. The sole parameter to the callback is the result of the * operation. */ void pwrite( int fd, const void* data, size_t size, off_t offset, SimpleAsyncIOCompletor completor); #if FOLLY_HAS_COROUTINES /* Coroutine version of pread(). * * Identical to pread() except that result is obtained by co_await instead of * callback. */ folly::coro::Task co_pread(int fd, void* buf, size_t size, off_t start); /* Coroutine version of pwrite(). * * Identical to pwrite() except that result is obtained by co_await instead of * callback. */ folly::coro::Task co_pwrite( int fd, const void* buf, size_t size, off_t start); #endif private: std::unique_ptr getOp(); void putOp(std::unique_ptr&&); void submitOp( Function preparer, SimpleAsyncIOCompletor completor); virtual void handlerReady(uint16_t events) noexcept override; template void init(); size_t maxRequests_; Executor::KeepAlive<> completionExecutor_; std::unique_ptr asyncIO_; Synchronized>> opsFreeList_; std::unique_ptr evb_; bool terminating_; Baton<> drainedBaton_; }; } // namespace folly