Module: check_mk
Branch: master
Commit: 0898286ba44d44da9a389c2fb3384f61c382a81f
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0898286ba44d44…
Author: Sven Panne <sp(a)mathias-kettner.de>
Date: Tue Jul 11 09:16:39 2017 +0200
Encapsulate select() calls, part 1
The problem: select() can only handle a fixed number of file descriptors,
1024 on most systems, and it has a very awkward low-level interface. We
will remove this restriction and clean up the related code in a series of
commits. Each commit will intentionally be small, but self-contained, easy
to understand, and most of the time mechanical. The whole series is
intended to be an example for improving an aspect of out SW in a structured
simple way, without the need for huge commits or great display of ingenuity.
This commit at hand only does something extremely simple and is a totally
mechanical refactoring: Put the select() call into a class, providing a 1:1
interface for now. Doesn't do very much in itself, but it is a starting
point for things to come...
Change-Id: I048ca6e7e2bbde7c3c4e2951baaef29874ed72c6
---
livestatus/src/InputBuffer.cc | 4 +++-
livestatus/src/OutputBuffer.cc | 4 +++-
livestatus/src/Poller.h | 41 +++++++++++++++++++++++++++++++++++++++++
livestatus/src/module.cc | 5 ++++-
livestatus/src/unixcat.cc | 4 +++-
5 files changed, 54 insertions(+), 4 deletions(-)
diff --git a/livestatus/src/InputBuffer.cc b/livestatus/src/InputBuffer.cc
index d76c94d..e2ecae8 100644
--- a/livestatus/src/InputBuffer.cc
+++ b/livestatus/src/InputBuffer.cc
@@ -31,6 +31,7 @@
#include <ratio>
#include "ChronoUtils.h"
#include "Logger.h"
+#include "Poller.h"
using std::chrono::milliseconds;
using std::chrono::system_clock;
@@ -205,12 +206,13 @@ InputBuffer::Result InputBuffer::readData() {
return Result::timeout;
}
+ Poller poller;
fd_set fds;
FD_ZERO(&fds);
FD_SET(_fd, &fds);
timeval tv = to_timeval(milliseconds(200));
- int retval = select(_fd + 1, &fds, nullptr, nullptr, &tv);
+ int retval = poller.poll(_fd + 1, &fds, nullptr, nullptr, &tv);
if (retval > 0 && FD_ISSET(_fd, &fds)) {
ssize_t r = read(_fd, &_readahead_buffer[_write_index],
_readahead_buffer.capacity() - _write_index);
diff --git a/livestatus/src/OutputBuffer.cc b/livestatus/src/OutputBuffer.cc
index 8cda43d..e44d46b 100644
--- a/livestatus/src/OutputBuffer.cc
+++ b/livestatus/src/OutputBuffer.cc
@@ -31,6 +31,7 @@
#include <ratio>
#include "ChronoUtils.h"
#include "Logger.h"
+#include "Poller.h"
using std::chrono::milliseconds;
using std::ostringstream;
@@ -78,12 +79,13 @@ void OutputBuffer::writeData(ostringstream &os) {
const char *buffer = static_cast<Hack *>(os.rdbuf())->base();
size_t bytes_to_write = os.tellp();
while (!_termination_flag && bytes_to_write > 0) {
+ Poller poller;
fd_set fds;
FD_ZERO(&fds);
FD_SET(_fd, &fds);
timeval tv = to_timeval(milliseconds(100));
- int retval = select(_fd + 1, nullptr, &fds, nullptr, &tv);
+ int retval = poller.poll(_fd + 1, nullptr, &fds, nullptr, &tv);
if (retval > 0 && FD_ISSET(_fd, &fds)) {
ssize_t bytes_written = write(_fd, buffer, bytes_to_write);
if (bytes_written == -1) {
diff --git a/livestatus/src/Poller.h b/livestatus/src/Poller.h
new file mode 100644
index 0000000..71e2090
--- /dev/null
+++ b/livestatus/src/Poller.h
@@ -0,0 +1,41 @@
+// +------------------------------------------------------------------+
+// | ____ _ _ __ __ _ __ |
+// | / ___| |__ ___ ___| | __ | \/ | |/ / |
+// | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
+// | | |___| | | | __/ (__| < | | | | . \ |
+// | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
+// | |
+// | 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 Poller_h
+#define Poller_h
+
+#include "config.h" // IWYU pragma: keep
+#include <sys/select.h>
+
+class Poller {
+public:
+ Poller() {}
+
+ int poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout) {
+ return select(nfds, readfds, writefds, exceptfds, timeout);
+ }
+};
+
+#endif // Poller_h
diff --git a/livestatus/src/module.cc b/livestatus/src/module.cc
index 9070545..8f0ca4e 100644
--- a/livestatus/src/module.cc
+++ b/livestatus/src/module.cc
@@ -54,6 +54,7 @@
#include "Logger.h"
#include "MonitoringCore.h"
#include "OutputBuffer.h"
+#include "Poller.h"
#include "Store.h"
#include "StringUtils.h"
#include "TimeperiodsCache.h"
@@ -202,10 +203,12 @@ void *main_thread(void *data) {
tv.tv_sec = 2;
tv.tv_usec = 500 * 1000;
+ Poller poller;
fd_set fds;
FD_ZERO(&fds);
FD_SET(g_unix_socket, &fds);
- int retval = select(g_unix_socket + 1, &fds, nullptr, nullptr, &tv);
+ int retval =
+ poller.poll(g_unix_socket + 1, &fds, nullptr, nullptr, &tv);
if (retval > 0 && FD_ISSET(g_unix_socket, &fds)) {
int cc = accept(g_unix_socket, nullptr, nullptr);
if (cc > g_max_fd_ever) {
diff --git a/livestatus/src/unixcat.cc b/livestatus/src/unixcat.cc
index 6a0555c..f381129 100644
--- a/livestatus/src/unixcat.cc
+++ b/livestatus/src/unixcat.cc
@@ -34,6 +34,7 @@
#include <cstring>
#include <iostream>
#include <string>
+#include "Poller.h"
using std::cerr;
using std::endl;
@@ -55,13 +56,14 @@ void printErrno(const string &msg) {
}
ssize_t read_with_timeout(int from, char *buffer, int size, int us) {
+ Poller poller;
fd_set fds;
FD_ZERO(&fds);
FD_SET(from, &fds);
struct timeval tv;
tv.tv_sec = us / 1000000;
tv.tv_usec = us % 1000000;
- int retval = select(from + 1, &fds, nullptr, nullptr, &tv);
+ int retval = poller.poll(from + 1, &fds, nullptr, nullptr, &tv);
if (retval > 0) {
return read(from, buffer, size);
}
Module: check_mk
Branch: master
Commit: 87b75247651c8f17ad3e6cd5e6793be9d8af58a1
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=87b75247651c8f…
Author: Sven Panne <sp(a)mathias-kettner.de>
Date: Tue Jul 11 13:18:05 2017 +0200
Encapsulate select() calls, part 5
Handle interrupted select() system call correctly. Previously we did this
only in one place by hand, but now that select() is centralized, we can fix
this easily.
Change-Id: I6cf5e1285679af0794a0563b36bb7a51597ef8ae
---
livestatus/src/Poller.h | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/livestatus/src/Poller.h b/livestatus/src/Poller.h
index e4328c2..9484ce1 100644
--- a/livestatus/src/Poller.h
+++ b/livestatus/src/Poller.h
@@ -27,6 +27,7 @@
#include "config.h" // IWYU pragma: keep
#include <sys/select.h>
+#include <cerrno>
#include "ChronoUtils.h"
class Poller {
@@ -36,8 +37,16 @@ public:
template <typename Rep, typename Period>
int poll(int nfds, fd_set *readfds, fd_set *writefds,
std::chrono::duration<Rep, Period> timeout) {
+ int retval;
timeval tv = to_timeval(timeout);
- return select(nfds, readfds, writefds, nullptr, &tv);
+ // I/O primitives can fail when interrupted by a signal, so we should
+ // retry the operation. In the plain C world, this is already
+ // encapsulated in e.g. glibc's TEMP_FAILURE_RETRY macro, see:
+ // https://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.h…
+ do {
+ retval = select(nfds, readfds, writefds, nullptr, &tv);
+ } while (retval == -1 && errno == EINTR);
+ return retval;
}
};