149 lines
4.5 KiB
Diff
149 lines
4.5 KiB
Diff
From 6d4f36c2c7f782af31eca7eca63310791a4f8e93 Mon Sep 17 00:00:00 2001
|
|
From: Zdenek Kabelac <zkabelac@redhat.com>
|
|
Date: Wed, 10 Apr 2019 12:50:53 +0200
|
|
Subject: [PATCH] libdaemon: use pselect to avoid condition checking race
|
|
|
|
To avoid tiny race on checking arrival of signal and entering select
|
|
(that can latter remain stuck as signal was already delivered) switch
|
|
to use pselect().
|
|
|
|
If it would needed, we can eventually add extra code for older systems
|
|
without pselect(), but there are probably no such ancient systems in
|
|
use.
|
|
---
|
|
daemons/lvmetad/lvmetad-core.c | 2 +-
|
|
daemons/lvmpolld/lvmpolld-core.c | 2 +-
|
|
libdaemon/server/daemon-server.c | 38 +++++++++++++++++++++++---------
|
|
libdaemon/server/daemon-server.h | 2 +-
|
|
4 files changed, 31 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
|
|
index c274880..fddec2e 100644
|
|
--- a/daemons/lvmetad/lvmetad-core.c
|
|
+++ b/daemons/lvmetad/lvmetad-core.c
|
|
@@ -2964,7 +2964,7 @@ static void usage(const char *prog, FILE *file)
|
|
int main(int argc, char *argv[])
|
|
{
|
|
signed char opt;
|
|
- struct timeval timeout;
|
|
+ struct timespec timeout;
|
|
daemon_idle di = { .ptimeout = &timeout };
|
|
lvmetad_state ls = { .log_config = "" };
|
|
daemon_state s = {
|
|
diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
|
|
index fd73272..f1056c3 100644
|
|
--- a/daemons/lvmpolld/lvmpolld-core.c
|
|
+++ b/daemons/lvmpolld/lvmpolld-core.c
|
|
@@ -915,7 +915,7 @@ int main(int argc, char *argv[])
|
|
int option_index = 0;
|
|
int client = 0, server = 0;
|
|
unsigned action = ACTION_MAX;
|
|
- struct timeval timeout;
|
|
+ struct timespec timeout;
|
|
daemon_idle di = { .ptimeout = &timeout };
|
|
struct lvmpolld_state ls = { .log_config = "" };
|
|
daemon_state s = {
|
|
diff --git a/libdaemon/server/daemon-server.c b/libdaemon/server/daemon-server.c
|
|
index 83f56db..53bee39 100644
|
|
--- a/libdaemon/server/daemon-server.c
|
|
+++ b/libdaemon/server/daemon-server.c
|
|
@@ -87,7 +87,7 @@ static int _is_idle(daemon_state s)
|
|
return s.idle && s.idle->is_idle && !s.threads->next;
|
|
}
|
|
|
|
-static struct timeval *_get_timeout(daemon_state s)
|
|
+static struct timespec *_get_timeout(daemon_state s)
|
|
{
|
|
return s.idle ? s.idle->ptimeout : NULL;
|
|
}
|
|
@@ -96,7 +96,7 @@ static void _reset_timeout(daemon_state s)
|
|
{
|
|
if (s.idle) {
|
|
s.idle->ptimeout->tv_sec = 1;
|
|
- s.idle->ptimeout->tv_usec = 0;
|
|
+ s.idle->ptimeout->tv_nsec = 0;
|
|
}
|
|
}
|
|
|
|
@@ -561,6 +561,8 @@ void daemon_start(daemon_state s)
|
|
thread_state _threads = { .next = NULL };
|
|
unsigned timeout_count = 0;
|
|
fd_set in;
|
|
+ sigset_t new_set, old_set;
|
|
+ int ret;
|
|
|
|
/*
|
|
* Switch to C locale to avoid reading large locale-archive file used by
|
|
@@ -628,8 +630,7 @@ void daemon_start(daemon_state s)
|
|
if (!s.foreground)
|
|
kill(getppid(), SIGTERM);
|
|
|
|
- /*
|
|
- * Use daemon_main for daemon-specific init and polling, or
|
|
+ /* Use daemon_main for daemon-specific init and polling, or
|
|
* use daemon_init for daemon-specific init and generic lib polling.
|
|
*/
|
|
|
|
@@ -643,22 +644,39 @@ void daemon_start(daemon_state s)
|
|
if (!s.daemon_init(&s))
|
|
failed = 1;
|
|
|
|
+ if (s.socket_fd >= FD_SETSIZE)
|
|
+ failed = 1; /* FD out of available selectable set */
|
|
+
|
|
+ sigfillset(&new_set);
|
|
+ sigprocmask(SIG_SETMASK, NULL, &old_set);
|
|
+
|
|
while (!failed) {
|
|
_reset_timeout(s);
|
|
FD_ZERO(&in);
|
|
FD_SET(s.socket_fd, &in);
|
|
- if (select(FD_SETSIZE, &in, NULL, NULL, _get_timeout(s)) < 0 && errno != EINTR)
|
|
- perror("select error");
|
|
+
|
|
+ sigprocmask(SIG_SETMASK, &new_set, NULL);
|
|
+ if (_shutdown_requested && !s.threads->next) {
|
|
+ sigprocmask(SIG_SETMASK, &old_set, NULL);
|
|
+ INFO(&s, "%s shutdown requested", s.name);
|
|
+ break;
|
|
+ }
|
|
+ ret = pselect(s.socket_fd + 1, &in, NULL, NULL, _get_timeout(s), &old_set);
|
|
+ sigprocmask(SIG_SETMASK, &old_set, NULL);
|
|
+
|
|
+ if (ret < 0) {
|
|
+ if (errno != EINTR && errno != EAGAIN &&
|
|
+ (EWOULDBLOCK == EAGAIN || errno != EWOULDBLOCK))
|
|
+ perror("select error");
|
|
+ continue;
|
|
+ }
|
|
+
|
|
if (FD_ISSET(s.socket_fd, &in)) {
|
|
timeout_count = 0;
|
|
_handle_connect(s);
|
|
}
|
|
-
|
|
_reap(s, 0);
|
|
|
|
- if (_shutdown_requested && !s.threads->next)
|
|
- break;
|
|
-
|
|
/* s.idle == NULL equals no shutdown on timeout */
|
|
if (_is_idle(s)) {
|
|
DEBUGLOG(&s, "timeout occured");
|
|
diff --git a/libdaemon/server/daemon-server.h b/libdaemon/server/daemon-server.h
|
|
index 2b9ceac..e77ac20 100644
|
|
--- a/libdaemon/server/daemon-server.h
|
|
+++ b/libdaemon/server/daemon-server.h
|
|
@@ -47,7 +47,7 @@ struct timeval;
|
|
typedef struct {
|
|
volatile unsigned is_idle;
|
|
unsigned max_timeouts;
|
|
- struct timeval *ptimeout;
|
|
+ struct timespec *ptimeout;
|
|
} daemon_idle;
|
|
|
|
struct daemon_state;
|
|
--
|
|
2.19.1
|
|
|