Module: check_mk
Branch: master
Commit: c7cc64523f573cbfcb7df852f8d9715ce01d0185
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=c7cc64523f573c…
Author: Sven Panne <sp(a)mathias-kettner.de>
Date: Wed Jul 12 14:52:04 2017 +0200
Encapsulate select() calls, part 11
Generalize the interface a bit: Instead of setting/testing a single kind of
event at a time, use a set of polling events. The former interface was OK
for the underlying select()-based implementation, but it was inadequate for
a future poll()-based implementation.
To use the involved bit masks in a type-safe way, a separate header
containing templated operators is introduced. This seems to be overkill for
the task at hand, but we can nicely use this at other places later.
Alas, this commit contains some tiny fixes to make cppcheck and clang-tidy
happy again. There seem to be some heuristics which have been triggered
accidentally, so let's just fix them now.
Change-Id: I29e788d8fb763778d1125f1a1a5543a4e97090aa
---
livestatus/src/BitMask.h | 99 ++++++++++++++++++++++++++++++++++++++
livestatus/src/InputBuffer.cc | 4 +-
livestatus/src/OutputBuffer.cc | 4 +-
livestatus/src/Poller.h | 35 +++++++++++---
livestatus/src/TableEventConsole.h | 2 +-
livestatus/src/module.cc | 5 +-
livestatus/src/unixcat.cc | 2 +-
7 files changed, 136 insertions(+), 15 deletions(-)
diff --git a/livestatus/src/BitMask.h b/livestatus/src/BitMask.h
new file mode 100644
index 0000000..3e4fcb0
--- /dev/null
+++ b/livestatus/src/BitMask.h
@@ -0,0 +1,99 @@
+// +------------------------------------------------------------------+
+// | ____ _ _ __ __ _ __ |
+// | / ___| |__ ___ ___| | __ | \/ | |/ / |
+// | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+// | | |___| | | | __/ (__| < | | | | . \ |
+// | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+// | |
+// | Copyright Mathias Kettner 2017 mk(a)mathias-kettner.de |
+// +------------------------------------------------------------------+
+//
+// This file is part of Check_MK.
+// The official homepage is at
http://mathias-kettner.de/check_mk.
+//
+// check_mk is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation in version 2. check_mk is distributed
+// in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
+// out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU General Public License for more de-
+// tails. You should have received a copy of the GNU General Public
+// License along with GNU Make; see the file COPYING. If not, write
+// to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+// Boston, MA 02110-1301 USA.
+
+#ifndef BitMask_h
+#define BitMask_h
+
+#include "config.h" // IWYU pragma: keep
+#include <type_traits>
+
+namespace mk {
+// Return the enumerator's value as a compile-time constant, see Scott Meyer's
+// "Effective Modern C++", item 10.
+template <typename Enum>
+constexpr auto toUType(Enum e) noexcept {
+ return static_cast<std::underlying_type_t<Enum>>(e);
+}
+
+// A marker trait which enables the bit mask operators
+template <typename Enum>
+struct is_bit_mask {
+ static const bool value = false;
+};
+
+// A helper macro to make the use sites of the marker trait less verbose
+#define IS_BIT_MASK(ENUM) \
+ namespace mk { \
+ template <> \
+ struct is_bit_mask<ENUM> { \
+ static const bool value = true; \
+ }; \
+ }
+
+// A helper template to make template definitions a bit shorter
+template <typename T>
+constexpr bool is_bit_mask_v = is_bit_mask<T>::value;
+} // namespace
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline constexpr Enum operator&(Enum x, Enum y) {
+ return x &= y;
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline constexpr Enum operator|(Enum x, Enum y) {
+ return x |= y;
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline constexpr Enum operator^(Enum x, Enum y) {
+ return x ^= y;
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline constexpr Enum operator~(Enum x) {
+ return Enum(~mk::toUType(x));
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline Enum &operator|=(Enum &x, Enum y) {
+ return x = Enum(mk::toUType(x) | mk::toUType(y));
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline const Enum &operator&=(Enum &x, Enum y) {
+ return x = Enum(mk::toUType(x) & mk::toUType(y));
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline Enum &operator^=(Enum &x, Enum y) {
+ return x = Enum(mk::toUType(x) ^ mk::toUType(y));
+}
+
+template <typename Enum, typename =
std::enable_if_t<mk::is_bit_mask_v<Enum>>>
+inline bool is_empty_bit_mask(Enum x) {
+ return x == Enum(0);
+}
+
+#endif // BitMask_h
diff --git a/livestatus/src/InputBuffer.cc b/livestatus/src/InputBuffer.cc
index ee04621..ecc3a13 100644
--- a/livestatus/src/InputBuffer.cc
+++ b/livestatus/src/InputBuffer.cc
@@ -205,9 +205,9 @@ InputBuffer::Result InputBuffer::readData() {
}
Poller poller;
- poller.addReadFD(_fd);
+ poller.addFileDescriptor(_fd, PollEvents::in);
int retval = poller.poll(milliseconds(200));
- if (retval > 0 && poller.isReadFDSet(_fd)) {
+ if (retval > 0 && poller.isFileDescriptorSet(_fd, PollEvents::in)) {
ssize_t r = read(_fd, &_readahead_buffer[_write_index],
_readahead_buffer.capacity() - _write_index);
if (r < 0) {
diff --git a/livestatus/src/OutputBuffer.cc b/livestatus/src/OutputBuffer.cc
index cbe565b..9417b46 100644
--- a/livestatus/src/OutputBuffer.cc
+++ b/livestatus/src/OutputBuffer.cc
@@ -78,9 +78,9 @@ void OutputBuffer::writeData(ostringstream &os) {
size_t bytes_to_write = os.tellp();
while (!_termination_flag && bytes_to_write > 0) {
Poller poller;
- poller.addWriteFD(_fd);
+ poller.addFileDescriptor(_fd, PollEvents::out);
int retval = poller.poll(milliseconds(100));
- if (retval > 0 && poller.isWriteFDSet(_fd)) {
+ if (retval > 0 && poller.isFileDescriptorSet(_fd, PollEvents::out)) {
ssize_t bytes_written = write(_fd, buffer, bytes_to_write);
if (bytes_written == -1) {
generic_error ge("could not write " +
diff --git a/livestatus/src/Poller.h b/livestatus/src/Poller.h
index 976acf5..27dd99f 100644
--- a/livestatus/src/Poller.h
+++ b/livestatus/src/Poller.h
@@ -29,8 +29,12 @@
#include <sys/select.h>
#include <algorithm>
#include <cerrno>
+#include "BitMask.h"
#include "ChronoUtils.h"
+enum class PollEvents { in = 1 << 0, out = 1 << 1 };
+IS_BIT_MASK(PollEvents);
+
class Poller {
public:
Poller() {
@@ -53,20 +57,37 @@ public:
return retval;
}
- void addReadFD(int fd) { addFD(fd, _readfds); }
- void addWriteFD(int fd) { addFD(fd, _writefds); }
+ void addFileDescriptor(int fd, PollEvents e) {
+ addFileDescriptor(fd, e, PollEvents::in, _readfds);
+ addFileDescriptor(fd, e, PollEvents::out, _writefds);
+ }
- bool isReadFDSet(int fd) const { return FD_ISSET(fd, &_readfds); }
- bool isWriteFDSet(int fd) const { return FD_ISSET(fd, &_writefds); }
+ bool isFileDescriptorSet(int fd, PollEvents e) const {
+ return isFileDescriptorSet(fd, e, PollEvents::in, _readfds) ||
+ isFileDescriptorSet(fd, e, PollEvents::out, _writefds);
+ }
private:
+#ifdef __clang_analyzer__
+ // Workaround for
https://llvm.org/bugs/show_bug.cgi?id=8920
+ fd_set _readfds{};
+ fd_set _writefds{};
+#else
fd_set _readfds;
fd_set _writefds;
+#endif
int _maxfd;
- void addFD(int fd, fd_set &fds) {
- FD_SET(fd, &fds);
- _maxfd = std::max(_maxfd, fd);
+ void addFileDescriptor(int fd, PollEvents e, PollEvents mask, fd_set &fds) {
+ if (!is_empty_bit_mask(e & mask)) {
+ FD_SET(fd, &fds);
+ _maxfd = std::max(_maxfd, fd);
+ }
+ }
+
+ bool isFileDescriptorSet(int fd, PollEvents e, PollEvents mask,
+ const fd_set &fds) const {
+ return !is_empty_bit_mask(e & mask) && FD_ISSET(fd, &fds);
}
};
diff --git a/livestatus/src/TableEventConsole.h b/livestatus/src/TableEventConsole.h
index 7745898..7357d03 100644
--- a/livestatus/src/TableEventConsole.h
+++ b/livestatus/src/TableEventConsole.h
@@ -69,7 +69,7 @@ protected:
public:
EventConsoleColumn(Column &column, T default_value,
- std::function<T(std::string)> f)
+ const std::function<T(std::string)> &f)
: _column(column), _default_value(default_value), _f(f) {}
std::string getRaw(ECRow *row) const {
diff --git a/livestatus/src/module.cc b/livestatus/src/module.cc
index 3e7907b..638de13 100644
--- a/livestatus/src/module.cc
+++ b/livestatus/src/module.cc
@@ -202,9 +202,10 @@ void *main_thread(void *data) {
do_statistics();
Poller poller;
- poller.addReadFD(g_unix_socket);
+ poller.addFileDescriptor(g_unix_socket, PollEvents::in);
int retval = poller.poll(milliseconds(2500));
- if (retval > 0 && poller.isReadFDSet(g_unix_socket)) {
+ if (retval > 0 &&
+ poller.isFileDescriptorSet(g_unix_socket, PollEvents::in)) {
int cc = accept(g_unix_socket, nullptr, nullptr);
if (cc > g_max_fd_ever) {
g_max_fd_ever = cc;
diff --git a/livestatus/src/unixcat.cc b/livestatus/src/unixcat.cc
index eb58200..ff510f6 100644
--- a/livestatus/src/unixcat.cc
+++ b/livestatus/src/unixcat.cc
@@ -60,7 +60,7 @@ void printErrno(const string &msg) {
ssize_t read_with_timeout(int from, char *buffer, int size,
microseconds timeout) {
Poller poller;
- poller.addReadFD(from);
+ poller.addFileDescriptor(from, PollEvents::in);
return poller.poll(timeout) > 0 ? read(from, buffer, size) : -2;
}