/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://llvm.org/LICENSE.txt * * 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. */ #include #if !UNIFEX_NO_LIBURING #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace unifex; using namespace unifex::linuxos; using namespace std::chrono_literals; template auto discard_value(S&& s) { return then((S&&)s, [](auto&&...) noexcept {}); } static constexpr unsigned char data[6] = {'h', 'e', 'l', 'l', 'o', '\n'}; // This could be made generic across any scheduler that supports the // async_write_only_file() CPO. auto write_new_file(io_uring_context::scheduler s, const char* path) { return let_value_with( [s, path]() { // Call the 'open_file_write_only' CPO with the scheduler. // This will return a file object that satisfies an // async-write-file concept. return open_file_write_only(s, path); }, [](io_uring_context::async_write_only_file& file) { const auto buffer = as_bytes(span{data}); // Start 8 concurrent writes to the file at different offsets. return discard_value(when_all( // Calls the 'async_write_some_at()' CPO on the file object // returned from 'open_file_write_only()'. async_write_some_at(file, 0, buffer), async_write_some_at(file, 1 * buffer.size(), buffer), async_write_some_at(file, 2 * buffer.size(), buffer), async_write_some_at(file, 3 * buffer.size(), buffer), async_write_some_at(file, 4 * buffer.size(), buffer), async_write_some_at(file, 5 * buffer.size(), buffer), async_write_some_at(file, 6 * buffer.size(), buffer), async_write_some_at(file, 7 * buffer.size(), buffer))); }); } auto read_file(io_uring_context::scheduler s, const char* path) { return let_value_with( [s, path]() { return open_file_read_only(s, path); }, [buffer = std::vector{}](auto& file) mutable { buffer.resize(100); return then( async_read_some_at( file, 0, as_writable_bytes(span{buffer.data(), buffer.size() - 1})), [&](ssize_t bytesRead) { std::printf("read %zi bytes\n", bytesRead); buffer[bytesRead] = '\0'; std::printf("contents: %s\n", buffer.data()); }); }); } int main() { io_uring_context ctx; inplace_stop_source stopSource; std::thread t{[&] { ctx.run(stopSource.get_token()); }}; scope_guard stopOnExit = [&]() noexcept { stopSource.request_stop(); t.join(); }; auto scheduler = ctx.get_scheduler(); try { { auto startTime = std::chrono::steady_clock::now(); inplace_stop_source timerStopSource; sync_wait( with_query_value( when_all( then( schedule_at(scheduler, now(scheduler) + 1s), []() { std::printf("timer 1 completed (1s)\n"); }), then( schedule_at(scheduler, now(scheduler) + 2s), []() { std::printf("timer 2 completed (2s)\n"); }), then( schedule_at(scheduler, now(scheduler) + 1500ms), [&]() { std::printf("timer 3 completed (1.5s) cancelling\n"); timerStopSource.request_stop(); })), get_stop_token, timerStopSource.get_token())); auto endTime = std::chrono::steady_clock::now(); std::printf( "completed in %i ms\n", (int)std::chrono::duration_cast( endTime - startTime) .count()); } sync_wait(sequence( just_from([] { std::printf("writing file\n"); }), write_new_file(scheduler, "test.txt"), just_from([] { std::printf("write completed, waiting 1s\n"); }), then( schedule_at(scheduler, now(scheduler) + 1s), []() { std::printf("timer 1 completed (1s)\n"); }), just_from([] { std::printf("reading file concurrently\n"); }), when_all( read_file(scheduler, "test.txt"), read_file(scheduler, "test.txt")))); } catch (const std::exception& ex) { std::printf("error: %s\n", ex.what()); } return 0; } #else // UNIFEX_NO_LIBURING #include int main() { printf("liburing support not found\n"); return 0; } #endif // UNIFEX_NO_LIBURING