diff --git a/emper/Emper.cpp b/emper/Emper.cpp index 2c1c779e9f25216a3ad37e98a8abe16650d71159..c9f6be84169409faf91499385fb6cc53c1d8fabd 100644 --- a/emper/Emper.cpp +++ b/emper/Emper.cpp @@ -15,6 +15,7 @@ #include "emper-version.h" #include "emper.hpp" #include "io/Future.hpp" +#include "lib/LinuxVersion.hpp" void async(Fiber* fiber) { assert(fiber != nullptr); @@ -44,6 +45,8 @@ void async(const Fiber::fiber_fun0_t& function, workeraffinity_t* affinity) { namespace emper { +bool IO_MUST_INVALIDATE_BROKEN_CHAIN = EMPER_LINUX_LT("5.15.0"); + auto getFullVersion() -> std::string { return EMPER_FULL_VERSION; } static void ensure_no_current_runtime() { diff --git a/emper/Emper.hpp b/emper/Emper.hpp index c87e99100b7ddcd950f8920f4140285fb8b3dfbc..78736f3c93835e51010025719b5c885a48f6ba6b 100644 --- a/emper/Emper.hpp +++ b/emper/Emper.hpp @@ -130,6 +130,16 @@ static const bool IO_URING_SQPOLL = #endif ; +// Initialize this bool in Emper.cpp because it needs code evaluation +// (LinuxVersion::compare) during runtime. +// Using a static variable here means EACH object file including this header has to +// evaluate the needed code during library initialization. +// An extern variable results in a single execution during initialization of the +// Emper.cpp object. +// This also has the advantage that the probability we crash because printing +// warnings during the comparison use not yet initialized components is reduced. +extern bool IO_MUST_INVALIDATE_BROKEN_CHAIN; + static const bool IO_URING_SHARED_WQ = #ifdef EMPER_IO_URING_SHARED_WQ true diff --git a/emper/io/IoContext.cpp b/emper/io/IoContext.cpp index bfd680a340fed2d5e50be02da4583970dd66910c..6a867a05893fed7fecd757acee78caf17a7b2c18 100644 --- a/emper/io/IoContext.cpp +++ b/emper/io/IoContext.cpp @@ -197,7 +197,14 @@ void IoContext::submitAndWait(Future &future, unsigned wait_nr) { // broken chains. This means that all sqes in a chain except the broken one will // result in cqes with result -ECANCELD and the invalid one will // generate a cqe with the appropriate error code - if (unlikely(static_cast<unsigned>(submitted) < prepared)) { + + // When 5.15 is released with + // https://lore.kernel.org/io-uring/180ec124-79b1-2274-4570-9b0d6620d512@linux.alibaba.com/T/#t + // the kernel will consume the whole broken chain and we + // don't need to manually invalidate not submitted sqes. + // This allows SQPOLL to work for invalid chains. + if (unlikely(static_cast<unsigned>(submitted) < prepared) && + emper::IO_MUST_INVALIDATE_BROKEN_CHAIN) { cancelUnsubmittedChainParts<callerEnvironment>(future); } diff --git a/emper/lib/LinuxVersion.cpp b/emper/lib/LinuxVersion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f37e5f362e0b865f429c6b317bd49e7b1748d0af --- /dev/null +++ b/emper/lib/LinuxVersion.cpp @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#include "lib/LinuxVersion.hpp" + +#include <cassert> +#include <cerrno> +#include <cstdlib> + +#include "Common.hpp" +#include "Debug.hpp" + +static auto checked_strtol(const std::string& s) -> long { + static const int DECIMAL = 10; + char* endptr; + const char* startptr = s.c_str(); + errno = 0; + + long res = strtol(startptr, &endptr, DECIMAL); + if (errno != 0) { + DIE_MSG_ERRNO("strtol failed"); + } + + if (endptr == startptr) { + DIE_MSG("strtol found no digits in " << s); + } + + if (endptr != startptr + s.size()) { + LOGW("LinuxVersion compare ignored non digits in " << s) + } + + return res; +} + +namespace emper::lib { + +LinuxVersion LinuxVersion::linuxVersion; + +// Returns 1 if s is smaller, -1 if this is smaller, 0 if equal +auto LinuxVersion::compare(const std::string& s) -> int { + size_t last_dot_pos = 0, last_dot_pos2 = 0; + + for (;;) { + size_t dot_pos = this->version.find('.', last_dot_pos); + // We run out of parts to compare the versions must be equal + if (dot_pos == std::string::npos) return 0; + + size_t dot_pos2 = s.find('.', last_dot_pos2); + assert(dot_pos2 != std::string::npos); + + long n1 = checked_strtol(this->version.substr(last_dot_pos, dot_pos - last_dot_pos)); + long n2 = checked_strtol(s.substr(last_dot_pos2, dot_pos2 - last_dot_pos2)); + + if (n1 > n2) return 1; + + if (n1 < n2) return -1; + + last_dot_pos = dot_pos + 1; + last_dot_pos2 = dot_pos2 + 1; + } +} + +} // namespace emper::lib diff --git a/emper/lib/LinuxVersion.hpp b/emper/lib/LinuxVersion.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6256cc40210261e7f413bb0f34cec92e03f02ead --- /dev/null +++ b/emper/lib/LinuxVersion.hpp @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Fischer +#pragma once + +#include <sys/utsname.h> + +#include <string> + +namespace emper::lib { +class LinuxVersion { + std::string version; + + auto compare(const std::string& s) -> int; + + public: + static LinuxVersion linuxVersion; + + LinuxVersion() { + struct utsname buf; + uname(&buf); + this->version = std::string(buf.release); + } + + auto operator>(const std::string& s) -> bool { return compare(s) > 0; } + + auto operator<(const std::string& s) -> bool { return compare(s) < 0; } + + auto operator==(const std::string& s) -> bool { return compare(s) == 0; } + + auto operator>=(const std::string& s) -> bool { return *this > s || *this == s; } + + auto operator<=(const std::string& s) -> bool { return *this < s || *this == s; } +}; +} // namespace emper::lib + +#define EMPER_LINUX_EQ(version) \ + ([]() -> bool { return empere::lib::LinuxVersion::linuxVersion == version; }()) +#define EMPER_LINUX_GT(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion > version; }()) +#define EMPER_LINUX_GE(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion >= version; }()) +#define EMPER_LINUX_LT(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion < version; }()) +#define EMPER_LINUX_LE(version) \ + ([]() -> bool { return emper::lib::LinuxVersion::linuxVersion <= version; }()) diff --git a/emper/lib/meson.build b/emper/lib/meson.build index 126bdd278cc7cb27c107f35b8c4f230a59f51dc8..88b68f898aa5ccb9a4a790bae234b640e48306c8 100644 --- a/emper/lib/meson.build +++ b/emper/lib/meson.build @@ -1,3 +1,4 @@ emper_cpp_sources += files( 'DebugUtil.cpp', + 'LinuxVersion.cpp', )