Hi guys,

I'm replying to this thread and adding Andrey and Veiko in Cc to keep
everyone up to date.

On Wed, Jun 08, 2016 at 10:17:19AM +0900, Simon Horman wrote:
> Lukas, could you try this?
> 
> diff --git a/src/checks.c b/src/checks.c
> index c4ac947b6051..e65d28f7c3c6 100644
> --- a/src/checks.c
> +++ b/src/checks.c
> @@ -1836,6 +1836,12 @@ static int connect_proc_chk(struct task *t)
>       if (pid == 0) {
>               /* Child */
>               extern char **environ;
> +
> +             if ((global.mode & MODE_QUIET) && !(global.mode & 
> MODE_VERBOSE)) {
> +                     close(0);
> +                     close(1);
> +             }
> +
>               environ = check->envp;
>               extchk_setenv(check, EXTCHK_HAPROXY_SERVER_CURCONN, 
> ultoa_r(s->cur_sess, buf, sizeof(buf)));
>               execvp(px->check_command, check->argv);

So since this patch we got Andrey's report and figured other issues
caused by sharing FDs between the processes (namely the fact that
automatic FD deletion doesn't happen in epoll until the child closes
it as well, possibly causing polling loops or fake event reports).

Thus I went down the safe route for now, by closing *all* FDs. This is
fast enough, on my machine I can close around 17 million FDs per second.
However I liked Simon's approach above consisting in keeping stdin/stdout/
stderr open when in verbose mode. That's very handy to debug.

While testing this change, I discovered a very interesting issue. My
process would randomly segfault after a delay ranging from 1 to 10
seconds. The core files didn't make any sense, proving that the memory
was corrupted. In the end I found the culprit. The problem is random
signal delivery. In the signal handler, a call to task_wakeup() is
made, and this sometimes destroys the scheduler when it's already in
the signal handler, as the rq_next pointer is sometimes nulled then
dereferenced, and sometimes the ebtree structure is corrupted. So I
changed this to make use of the asynchronous signal delivery and now
it's OK since the functions are called after the poll loop.

This made me remember that Veiko who used to experience random segfaults
with zlib also has external checks configured and also had a non-sensical
core file, and zlib has a few orders of magniture higher latency than the
rest of the process, that makes it much more likely that a signal is
delivered here than anywhere else.

Thus I backported all of this to 1.6 planning for 1.6.6. It would be nice
if the people affected with issues could give it a try this week (either
from git or just wait for tomorrow morning to get the latest snapshot).

I also developped a patch to block all signals out of the poll loop. This
makes the code cleaner but I realized that it only improves the performance
for fork-limited workloads and will decrease it for regular workloads. So
for now it remains unmerged before I run more tests. On Linux we can use
epoll_pwait() to remove a few syscalls so the impact might be less important.
Anyway I suspect that over the longterm we'll go this way.

Thanks to all those who helped on this, and do not hesitate to report
any remaining issue!

Willy


Reply via email to