mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-31 18:41:39 +00:00
MEDIUM: mworker: leave when the master die
When the master die, the worker should exit too, this is achieved by checking if the FD of the socketpair/pipe was closed between the master and the worker. In the former architecture of the master-worker, there was only a pipe between the master and the workers, and it was easy to check an EOF on the pipe FD to exit() the worker. With the new architecture, we use a socketpair by process, and this socketpair is also used to accept new connections with the listener_accept() callback. This accept callback can't handle the EOF and the exit of the process, because it's very specific to the master worker. This is why we transformed the mworker_pipe_handler() function in a wrapper which check if there is an EOF and exit the process, and if not call listener_accept() to achieve the accept.
This commit is contained in:
parent
5d05db8ce1
commit
7216032e6f
@ -2543,43 +2543,58 @@ void deinit(void)
|
||||
deinit_pollers();
|
||||
} /* end deinit() */
|
||||
|
||||
void mworker_pipe_handler(int fd)
|
||||
|
||||
|
||||
/* This is a wrapper for the sockpair FD, It tests if the socket received an
|
||||
* EOF, if not, it calls listener_accept */
|
||||
void mworker_accept_wrapper(int fd)
|
||||
{
|
||||
char c;
|
||||
int ret;
|
||||
|
||||
while (read(fd, &c, 1) == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
fd_cant_recv(fd);
|
||||
while (1) {
|
||||
ret = recv(fd, &c, 1, MSG_PEEK);
|
||||
if (ret == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN) {
|
||||
fd_cant_recv(fd);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
} else if (ret > 0) {
|
||||
listener_accept(fd);
|
||||
return;
|
||||
} else if (ret == 0) {
|
||||
/* At this step the master is down before
|
||||
* this worker perform a 'normal' exit.
|
||||
* So we want to exit with an error but
|
||||
* other threads could currently process
|
||||
* some stuff so we can't perform a clean
|
||||
* deinit().
|
||||
*/
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* At this step the master is down before
|
||||
* this worker perform a 'normal' exit.
|
||||
* So we want to exit with an error but
|
||||
* other threads could currently process
|
||||
* some stuff so we can't perform a clean
|
||||
* deinit().
|
||||
*/
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* should only be called once per process */
|
||||
/*
|
||||
* Should only be called once per process
|
||||
* This function register the accept wrapper for the sockpair of the master worker
|
||||
*/
|
||||
|
||||
void mworker_pipe_register()
|
||||
{
|
||||
if (fdtab[proc_self->ipc_fd[1]].owner)
|
||||
/* already initialized */
|
||||
return;
|
||||
/* The iocb should be already initialized with listener_accept */
|
||||
if (fdtab[proc_self->ipc_fd[1]].iocb != listener_accept)
|
||||
abort();
|
||||
|
||||
fcntl(proc_self->ipc_fd[1], F_SETFL, O_NONBLOCK);
|
||||
/* In multi-tread, we need only one thread to process
|
||||
* events on the pipe with master
|
||||
*/
|
||||
fd_insert(proc_self->ipc_fd[1], proc_self->ipc_fd, mworker_pipe_handler, 1);
|
||||
fd_insert(proc_self->ipc_fd[1], proc_self->ipc_fd, mworker_accept_wrapper, 1);
|
||||
fd_want_recv(proc_self->ipc_fd[1]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user