blob: 874536d0b4155ed3bc984848d121c661ee1b6e78 [file] [log] [blame]
/*
This file is part of libmicrohttpd
Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file lib/daemon_quiesce.c
* @brief main functions to quiesce a daemon
* @author Christian Grothoff
*/
#include "internal.h"
/**
* Stop accepting connections from the listening socket. Allows
* clients to continue processing, but stops accepting new
* connections. Note that the caller is responsible for closing the
* returned socket; however, if MHD is run using threads (anything but
* external select mode), it must not be closed until AFTER
* #MHD_stop_daemon has been called (as it is theoretically possible
* that an existing thread is still using it).
*
* Note that some thread modes require the caller to have passed
* #MHD_USE_ITC when using this API. If this daemon is
* in one of those modes and this option was not given to
* #MHD_start_daemon, this function will return #MHD_INVALID_SOCKET.
*
* @param daemon daemon to stop accepting new connections for
* @return old listen socket on success, #MHD_INVALID_SOCKET if
* the daemon was already not listening anymore, or
* was never started
* @ingroup specialized
*/
MHD_socket
MHD_daemon_quiesce (struct MHD_Daemon *daemon)
{
MHD_socket listen_socket;
if (MHD_INVALID_SOCKET == (listen_socket = daemon->listen_socket))
return MHD_INVALID_SOCKET;
if ( (daemon->disable_itc) &&
(MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode) )
{
#ifdef HAVE_MESSAGES
MHD_DLOG (daemon,
MHD_SC_SYSCALL_QUIESCE_REQUIRES_ITC,
"Using MHD_quiesce_daemon in this mode requires ITC.\n");
#endif
return MHD_INVALID_SOCKET;
}
if (NULL != daemon->worker_pool)
{
unsigned int i;
for (i = 0; i < daemon->worker_pool_size; i++)
{
struct MHD_Daemon *worker = &daemon->worker_pool[i];
worker->was_quiesced = true;
#ifdef EPOLL_SUPPORT
if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
(-1 != worker->epoll_fd) &&
(worker->listen_socket_in_epoll) )
{
if (0 != epoll_ctl (worker->epoll_fd,
EPOLL_CTL_DEL,
listen_socket,
NULL))
MHD_PANIC (_ ("Failed to remove listen FD from epoll set.\n"));
worker->listen_socket_in_epoll = false;
}
else
#endif
if (MHD_ITC_IS_VALID_ (worker->itc))
{
if (! MHD_itc_activate_ (worker->itc,
"q"))
MHD_PANIC (_ (
"Failed to signal quiesce via inter-thread communication channel.\n"));
}
}
daemon->was_quiesced = true;
#ifdef EPOLL_SUPPORT
if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) &&
(-1 != daemon->epoll_fd) &&
(daemon->listen_socket_in_epoll) )
{
if (0 != epoll_ctl (daemon->epoll_fd,
EPOLL_CTL_DEL,
listen_socket,
NULL))
MHD_PANIC ("Failed to remove listen FD from epoll set.\n");
daemon->listen_socket_in_epoll = false;
}
#endif
}
if ( (MHD_ITC_IS_VALID_ (daemon->itc)) &&
(! MHD_itc_activate_ (daemon->itc,
"q")) )
MHD_PANIC (_ (
"Failed to signal quiesce via inter-thread communication channel.\n"));
/* FIXME: we might want some bi-directional communication here
(in both the thread-pool and single-thread case!)
to be sure that the threads have stopped using the listen
socket, otherwise there is still the possibility of a race
between a thread accept()ing and the caller closing and
re-binding the socket. */return listen_socket;
}
/* end of daemon_quiesce.c */