From 3556a7bed5bbe67d4f33084529758e705ccc1782 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 18 May 2019 23:19:01 -0700 Subject: [PATCH] Read/write loop test working --- .clang-format | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 4 ++ Makefile | 38 +++++++++++++ README.md | 1 + test_loop | Bin 0 -> 144408 bytes test_loop.cc | 40 +++++++++++++ uring.cc | 122 ++++++++++++++++++++++++++++++++++++++++ uring.h | 64 +++++++++++++++++++++ 8 files changed, 420 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100755 test_loop create mode 100644 test_loop.cc create mode 100644 uring.cc create mode 100644 uring.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3c316f8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,151 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e990f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.a +*.so +*.o +*.swp diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..154c42e --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +FIRE_CXX ?= clang++ +FIRE_CXXFLAGS ?= -O3 -std=gnu++2a -Wall -Werror -Wextra -fPIE -fPIC -fstack-protector-strong -fsanitize=safe-stack -fsanitize=safe-stack +FIRE_LDFLAGS ?= -fuse-ld=gold -flto -Wl,-z,relro -Wl,-z,now +FIRE_LDLIBS ?= -lglog -lgflags -luring + +all: liburing++.a liburing++.o liburing++.so test_loop + +objects = uring.o + +liburing++.a: $(objects) + ar rcs $@ $^ + +liburing++.o: $(objects) + gold -z relro -z now -r --output=$@ $+ + +liburing++.so: $(objects) + $(FIRE_CXX) $(FIRE_CXXFLAGS) $(FIRE_LDFLAGS) -shared -o $@ $+ $(FIRE_LDLIBS) + +test_loop: test_loop.o uring.o + $(FIRE_CXX) $(FIRE_CXXFLAGS) $(FIRE_LDFLAGS) -pie -o $@ $+ $(FIRE_LDLIBS) + +%.o: %.cc *.h Makefile + $(FIRE_CXX) $(FIRE_CXXFLAGS) -c -o $@ $< + +clean: + rm --force *.so *.o *.a + +asan: + $(MAKE) clean + FIRE_CXXFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer -std=gnu++2a -fPIE -fPIC" $(MAKE) all + +tsan: + $(MAKE) clean + FIRE_CXXFLAGS="-O1 -g -fsanitize=thread -std=gnu++2a -fPIE -fPIC" $(MAKE) all + +ubsan: + $(MAKE) clean + FIRE_CXXFLAGS="-O1 -g -fsanitize=undefined -std=gnu++2a -fPIE -fPIC" $(MAKE) all diff --git a/README.md b/README.md new file mode 100644 index 0000000..c39f1b7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Idiomatic C++ wrapper around [liburing](http://git.kernel.dk/cgit/liburing/) diff --git a/test_loop b/test_loop new file mode 100755 index 0000000000000000000000000000000000000000..155c2aa26112bf9dc323ee026fca17bfb39eb9fa GIT binary patch literal 144408 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 z�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%0A-E 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 xIAoRoRQufmPNh8;2~O_+A#UK +#include + +int main(int argc, char* argv[]) { + google::InitGoogleLogging(argv[0]); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + uring::URing uring(1); + + int sv[2]; + PCHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); + + std::string foo("foo\n"); + + bool fired = false; + uring.write(sv[0], foo.data(), foo.size(), [&](int32_t res) { + fired = true; + LOG(INFO) << "write() res=" << res; + CHECK_EQ(res, 4); + }); + uring.Submit(); + uring.Wait(); + CHECK(fired); + + char buf[10]; + fired = false; + uring.read(sv[1], buf, 10, [&](int32_t res) { + fired = true; + LOG(INFO) << "read() res=" << res; + CHECK_EQ(res, 4); + CHECK_EQ(memcmp(buf, foo.data(), foo.size()), 0); + }); + uring.Submit(); + uring.Wait(); + CHECK(fired); + + CHECK_EQ(uring.Try(), false); +} diff --git a/uring.cc b/uring.cc new file mode 100644 index 0000000..292a5d7 --- /dev/null +++ b/uring.cc @@ -0,0 +1,122 @@ +#include "uring.h" + +#include + +namespace uring { + +URing::URing(uint32_t num_entries) + : ring_fd_(io_uring_queue_init(num_entries, &ring_, 0)), + entries_(num_entries * 3), + free_head_(&entries_.at(0)) { + PCHECK(ring_fd_ >= 0) << "io_uring_queue_init()"; + + // Chain the entries together into a list that we'll use as a free list for + // future allocation. + Entry *prev = nullptr; + for (auto &entry : entries_) { + entry.free_next = prev; + prev = &entry; + } +} + +URing::~URing() { io_uring_queue_exit(&ring_); } + +void URing::Submit() { io_uring_submit(&ring_); } + +void URing::Wait() { + io_uring_cqe *cqe; + PCHECK(io_uring_wait_cqe(&ring_, &cqe) == 0); + ProcessCQE(cqe); +} + +bool URing::Try() { + io_uring_cqe *cqe = nullptr; + PCHECK(io_uring_peek_cqe(&ring_, &cqe) == 0); + if (cqe) { + ProcessCQE(cqe); + return true; + } + return false; +} + +void URing::write(int fd, const void *buf, size_t count, + const std::function &callback) { + std::vector vecs{ + { + .iov_base = const_cast(buf), + .iov_len = count, + }, + }; + writev(fd, vecs, callback); +} + +void URing::writev(int fd, const std::vector &vecs, + const std::function &callback) { + pwritev(fd, vecs, 0, callback); +} + +void URing::pwritev(int fd, const std::vector &vecs, off_t offset, + const std::function &callback) { + auto *entry = GetEntry(callback); + entry->vecs = vecs; + + auto *sqe = GetSQE(); + io_uring_prep_writev(sqe, fd, entry->vecs.data(), entry->vecs.size(), offset); + io_uring_sqe_set_data(sqe, reinterpret_cast(entry)); +} + +void URing::read(int fd, const void *buf, size_t count, + const std::function &callback) { + std::vector vecs{ + { + .iov_base = const_cast(buf), + .iov_len = count, + }, + }; + readv(fd, vecs, callback); +} + +void URing::readv(int fd, const std::vector &vecs, + const std::function &callback) { + preadv(fd, vecs, 0, callback); +} + +void URing::preadv(int fd, const std::vector &vecs, off_t offset, + const std::function &callback) { + auto *entry = GetEntry(callback); + entry->vecs = vecs; + + auto *sqe = GetSQE(); + io_uring_prep_readv(sqe, fd, entry->vecs.data(), entry->vecs.size(), offset); + io_uring_sqe_set_data(sqe, reinterpret_cast(entry)); +} + +URing::Entry *URing::GetEntry( + const std::function &callback) { + CHECK(free_head_); + auto *entry = free_head_; + free_head_ = entry->free_next; + entry->callback = callback; + return entry; +} + +void URing::PutEntry(Entry *entry, int32_t res) { + entry->callback(res); + entry->free_next = free_head_; + free_head_ = entry; +} + +io_uring_sqe *URing::GetSQE() { + auto *sqe = io_uring_get_sqe(&ring_); + // TODO: automatically Submit() on full submit queue? spin? something else? + CHECK(sqe); + return sqe; +} + +void URing::ProcessCQE(io_uring_cqe *cqe) { + Entry *entry = reinterpret_cast(io_uring_cqe_get_data(cqe)); + PutEntry(entry, cqe->res); + io_uring_cqe_seen(&ring_, cqe); +} + +} // namespace uring diff --git a/uring.h b/uring.h new file mode 100644 index 0000000..ab12ad9 --- /dev/null +++ b/uring.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include + +namespace uring { + +// Not thread safe. Instantiate one per thread instead. +class URing { + public: + URing(uint32_t num_entries); + ~URing(); + + // TODO: write/writev don't work for files because they always use offset 0 + void write(int fd, const void *buf, size_t count, + const std::function &callback); + void writev(int fd, const std::vector &vecs, + const std::function &callback); + void pwritev(int fd, const std::vector &vecs, off_t offset, + const std::function &callback); + + // TODO: read/readv don't work for files because they always use offset 0 + void read(int fd, const void *buf, size_t count, + const std::function &callback); + void readv(int fd, const std::vector &vecs, + const std::function &callback); + void preadv(int fd, const std::vector &vecs, off_t offset, + const std::function &callback); + + // Submit all operations queued since the last Submit(). They must all be in + // a valid state when this is called. + void Submit(); + + // Wait for one operation to complete and synchronously call its callback. + void Wait(); + + // If an operation is complete, synchronously call its callback and return + // true. + bool Try(); + + private: + io_uring ring_; + int ring_fd_; + + struct Entry { + Entry *free_next; + std::vector vecs; + std::function callback; + }; + + std::vector entries_; + Entry *free_head_ = nullptr; + + Entry *GetEntry(const std::function &callback); + void PutEntry(Entry *entry, int32_t res); + + io_uring_sqe *GetSQE(); + + void ProcessCQE(io_uring_cqe *cqe); +}; + +} // namespace uring