165 lines
5.4 KiB
C++
165 lines
5.4 KiB
C++
/*
|
|
* 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 <unifex/config.hpp>
|
|
|
|
#if !UNIFEX_NO_LIBURING
|
|
|
|
#include <unifex/inplace_stop_token.hpp>
|
|
#include <unifex/just.hpp>
|
|
#include <unifex/let_value_with.hpp>
|
|
#include <unifex/linux/io_uring_context.hpp>
|
|
#include <unifex/scheduler_concepts.hpp>
|
|
#include <unifex/scope_guard.hpp>
|
|
#include <unifex/sequence.hpp>
|
|
#include <unifex/sync_wait.hpp>
|
|
#include <unifex/then.hpp>
|
|
#include <unifex/when_all.hpp>
|
|
#include <unifex/with_query_value.hpp>
|
|
#include <unifex/just_from.hpp>
|
|
|
|
#include <chrono>
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
using namespace unifex;
|
|
using namespace unifex::linuxos;
|
|
using namespace std::chrono_literals;
|
|
|
|
template<typename S>
|
|
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<char>{}](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<std::chrono::milliseconds>(
|
|
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 <cstdio>
|
|
int main() {
|
|
printf("liburing support not found\n");
|
|
return 0;
|
|
}
|
|
|
|
#endif // UNIFEX_NO_LIBURING
|