2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 22:45:39 +00:00

Synchronise stop listening operation for multi-layer transports

This commit introduces a primitive isc__nmsocket_stop() which performs
shutting down on a multilayered socket ensuring the proper order of
the operations.

The shared data within the socket object can be destroyed after the
call completed, as it is guaranteed to not be used from within the
context of other worker threads.
This commit is contained in:
Artem Boldariev
2022-10-14 20:45:40 +03:00
parent 55a184c13f
commit 5ab2c0ebb3
8 changed files with 114 additions and 32 deletions

View File

@@ -2536,6 +2536,9 @@ isc_nm_listenhttp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
sock->nchildren = sock->outer->nchildren; sock->nchildren = sock->outer->nchildren;
sock->fd = (uv_os_sock_t)-1; sock->fd = (uv_os_sock_t)-1;
isc__nmsocket_barrier_init(sock);
atomic_init(&sock->rchildren, sock->nchildren);
atomic_store(&sock->listening, true); atomic_store(&sock->listening, true);
*sockp = sock; *sockp = sock;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
@@ -2702,20 +2705,7 @@ isc__nm_http_stoplistening(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_httplistener); REQUIRE(sock->type == isc_nm_httplistener);
REQUIRE(isc_tid() == sock->tid); REQUIRE(isc_tid() == sock->tid);
if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, isc__nmsocket_stop(sock);
true)) {
UNREACHABLE();
}
atomic_store(&sock->listening, false);
atomic_store(&sock->closed, true);
sock->recv_cb = NULL;
sock->recv_cbarg = NULL;
if (sock->outer != NULL) {
isc_nm_stoplistening(sock->outer);
isc_nmsocket_close(&sock->outer);
}
} }
static void static void

View File

@@ -286,6 +286,7 @@ typedef enum isc__netievent_type {
netievent_sendcb, netievent_sendcb,
netievent_settlsctx, netievent_settlsctx,
netievent_sockstop, /* for multilayer sockets */
netievent_udplisten, netievent_udplisten,
netievent_udpstop, netievent_udpstop,
@@ -1060,6 +1061,7 @@ struct isc_nmsocket {
atomic_int_fast32_t active_child_connections; atomic_int_fast32_t active_child_connections;
bool barrier_initialised;
#ifdef NETMGR_TRACE #ifdef NETMGR_TRACE
void *backtrace[TRACE_SIZE]; void *backtrace[TRACE_SIZE];
int backtrace_size; int backtrace_size;
@@ -1678,6 +1680,9 @@ isc__nm_http_set_max_streams(isc_nmsocket_t *listener,
void void
isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0); isc__nm_async_settlsctx(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_sockstop(isc__networker_t *worker, isc__netievent_t *ev0);
void void
isc__nm_incstats(isc_nmsocket_t *sock, isc__nm_statid_t id); isc__nm_incstats(isc_nmsocket_t *sock, isc__nm_statid_t id);
/*%< /*%<
@@ -1764,6 +1769,27 @@ isc__nm_set_network_buffers(isc_nm_t *nm, uv_handle_t *handle);
* Sets the pre-configured network buffers size on the handle. * Sets the pre-configured network buffers size on the handle.
*/ */
void
isc__nmsocket_barrier_init(isc_nmsocket_t *listener);
/*%>
* Initialise the socket synchronisation barrier according to the
* number of children.
*/
void
isc__nmsocket_stop(isc_nmsocket_t *listener);
/*%>
* Broadcast "stop" event for a listener socket across all workers and
* wait its processing completion - then, stop and close the underlying
* transport listener socket.
*
* The primitive is used in multi-layer transport listener sockets to
* implement shutdown properly: after the broadcasted events has been
* processed it is safe to destroy the shared data within the listener
* socket (including shutting down the underlying transport listener
* socket).
*/
/* /*
* typedef all the netievent types * typedef all the netievent types
*/ */
@@ -1815,6 +1841,7 @@ NETIEVENT_SOCKET_HANDLE_TYPE(udpcancel);
NETIEVENT_SOCKET_QUOTA_TYPE(tcpaccept); NETIEVENT_SOCKET_QUOTA_TYPE(tcpaccept);
NETIEVENT_SOCKET_TLSCTX_TYPE(settlsctx); NETIEVENT_SOCKET_TLSCTX_TYPE(settlsctx);
NETIEVENT_SOCKET_TYPE(sockstop);
/* Now declared the helper functions */ /* Now declared the helper functions */
@@ -1864,6 +1891,7 @@ NETIEVENT_SOCKET_DECL(detach);
NETIEVENT_SOCKET_QUOTA_DECL(tcpaccept); NETIEVENT_SOCKET_QUOTA_DECL(tcpaccept);
NETIEVENT_SOCKET_TLSCTX_DECL(settlsctx); NETIEVENT_SOCKET_TLSCTX_DECL(settlsctx);
NETIEVENT_SOCKET_DECL(sockstop);
void void
isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result); isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result);

View File

@@ -483,6 +483,7 @@ process_netievent(void *arg) {
NETIEVENT_CASE(httpendpoints); NETIEVENT_CASE(httpendpoints);
NETIEVENT_CASE(settlsctx); NETIEVENT_CASE(settlsctx);
#endif #endif
NETIEVENT_CASE(sockstop);
NETIEVENT_CASE(connectcb); NETIEVENT_CASE(connectcb);
NETIEVENT_CASE(readcb); NETIEVENT_CASE(readcb);
@@ -558,6 +559,7 @@ NETIEVENT_SOCKET_DEF(detach);
NETIEVENT_SOCKET_QUOTA_DEF(tcpaccept); NETIEVENT_SOCKET_QUOTA_DEF(tcpaccept);
NETIEVENT_SOCKET_TLSCTX_DEF(settlsctx); NETIEVENT_SOCKET_TLSCTX_DEF(settlsctx);
NETIEVENT_SOCKET_DEF(sockstop);
void void
isc__nm_process_ievent(isc__networker_t *worker, isc__netievent_t *event) { isc__nm_process_ievent(isc__networker_t *worker, isc__netievent_t *event) {
@@ -715,6 +717,10 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree FLARG) {
isc__nm_http_cleanup_data(sock); isc__nm_http_cleanup_data(sock);
#endif #endif
if (sock->barrier_initialised) {
isc_barrier_destroy(&sock->barrier);
}
sock->magic = 0; sock->magic = 0;
#ifdef NETMGR_TRACE #ifdef NETMGR_TRACE
@@ -2103,6 +2109,66 @@ isc_nm_stoplistening(isc_nmsocket_t *sock) {
} }
} }
void
isc__nmsocket_stop(isc_nmsocket_t *listener) {
isc__netievent_sockstop_t ievent = { .sock = listener };
REQUIRE(VALID_NMSOCK(listener));
REQUIRE(listener->tid == isc_tid());
REQUIRE(listener->tid == 0);
if (!atomic_compare_exchange_strong(&listener->closing,
&(bool){ false }, true)) {
UNREACHABLE();
}
for (size_t i = 1; i < listener->nchildren; i++) {
isc__networker_t *worker =
&listener->worker->netmgr->workers[i];
isc__netievent_sockstop_t *ev =
isc__nm_get_netievent_sockstop(worker, listener);
isc__nm_enqueue_ievent(worker, (isc__netievent_t *)ev);
}
isc__nm_async_sockstop(listener->worker, (isc__netievent_t *)&ievent);
INSIST(atomic_load(&listener->rchildren) == 0);
if (!atomic_compare_exchange_strong(&listener->listening,
&(bool){ true }, false))
{
UNREACHABLE();
}
listener->accept_cb = NULL;
listener->accept_cbarg = NULL;
listener->recv_cb = NULL;
listener->recv_cbarg = NULL;
if (listener->outer != NULL) {
isc_nm_stoplistening(listener->outer);
isc__nmsocket_detach(&listener->outer);
}
atomic_store(&listener->closed, true);
}
void
isc__nmsocket_barrier_init(isc_nmsocket_t *listener) {
REQUIRE(listener->nchildren > 0);
isc_barrier_init(&listener->barrier, listener->nchildren);
listener->barrier_initialised = true;
}
void
isc__nm_async_sockstop(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_sockstop_t *ievent = (isc__netievent_sockstop_t *)ev0;
isc_nmsocket_t *listener = ievent->sock;
UNUSED(worker);
(void)atomic_fetch_sub(&listener->rchildren, 1);
isc_barrier_wait(&listener->barrier);
}
void void
isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq, isc__nm_connectcb(isc_nmsocket_t *sock, isc__nm_uvreq_t *uvreq,
isc_result_t eresult, bool async) { isc_result_t eresult, bool async) {

View File

@@ -408,7 +408,7 @@ isc_nm_listentcp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
sock->children = isc_mem_getx(worker->mctx, children_size, sock->children = isc_mem_getx(worker->mctx, children_size,
ISC_MEM_ZERO); ISC_MEM_ZERO);
isc_barrier_init(&sock->barrier, sock->nchildren); isc__nmsocket_barrier_init(sock);
sock->accept_cb = accept_cb; sock->accept_cb = accept_cb;
sock->accept_cbarg = accept_cbarg; sock->accept_cbarg = accept_cbarg;

View File

@@ -398,7 +398,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
sock->children = isc_mem_getx(worker->mctx, children_size, sock->children = isc_mem_getx(worker->mctx, children_size,
ISC_MEM_ZERO); ISC_MEM_ZERO);
isc_barrier_init(&sock->barrier, sock->nchildren); isc__nmsocket_barrier_init(sock);
sock->accept_cb = accept_cb; sock->accept_cb = accept_cb;
sock->accept_cbarg = accept_cbarg; sock->accept_cbarg = accept_cbarg;

View File

@@ -511,7 +511,7 @@ isc_nm_listentlsdns(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
sock->children = isc_mem_getx(worker->mctx, children_size, sock->children = isc_mem_getx(worker->mctx, children_size,
ISC_MEM_ZERO); ISC_MEM_ZERO);
isc_barrier_init(&sock->barrier, sock->nchildren); isc__nmsocket_barrier_init(sock);
sock->accept_cb = accept_cb; sock->accept_cb = accept_cb;
sock->accept_cbarg = accept_cbarg; sock->accept_cbarg = accept_cbarg;

View File

@@ -675,6 +675,13 @@ tlslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
REQUIRE(VALID_NMSOCK(tlslistensock)); REQUIRE(VALID_NMSOCK(tlslistensock));
REQUIRE(tlslistensock->type == isc_nm_tlslistener); REQUIRE(tlslistensock->type == isc_nm_tlslistener);
if (isc__nmsocket_closing(handle->sock) ||
isc__nmsocket_closing(tlslistensock) ||
!atomic_load(&tlslistensock->listening))
{
return (ISC_R_CANCELED);
}
/* /*
* We need to create a 'wrapper' tlssocket for this connection. * We need to create a 'wrapper' tlssocket for this connection.
*/ */
@@ -763,6 +770,10 @@ isc_nm_listentls(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
isc__nmsocket_attach(tlssock, &tlssock->outer->tlsstream.tlslistener); isc__nmsocket_attach(tlssock, &tlssock->outer->tlsstream.tlslistener);
isc__nmsocket_detach(&tsock); isc__nmsocket_detach(&tsock);
INSIST(result != ISC_R_UNSET); INSIST(result != ISC_R_UNSET);
tlssock->nchildren = tlssock->outer->nchildren;
isc__nmsocket_barrier_init(tlssock);
atomic_init(&tlssock->rchildren, tlssock->nchildren);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
atomic_store(&tlssock->listening, true); atomic_store(&tlssock->listening, true);
@@ -933,20 +944,7 @@ isc__nm_tls_stoplistening(isc_nmsocket_t *sock) {
REQUIRE(sock->tlsstream.tls == NULL); REQUIRE(sock->tlsstream.tls == NULL);
REQUIRE(sock->tlsstream.ctx == NULL); REQUIRE(sock->tlsstream.ctx == NULL);
if (!atomic_compare_exchange_strong(&sock->closing, &(bool){ false }, isc__nmsocket_stop(sock);
true)) {
UNREACHABLE();
}
atomic_store(&sock->listening, false);
atomic_store(&sock->closed, true);
sock->recv_cb = NULL;
sock->recv_cbarg = NULL;
if (sock->outer != NULL) {
isc_nm_stoplistening(sock->outer);
isc__nmsocket_detach(&sock->outer);
}
} }
static void static void

View File

@@ -155,7 +155,7 @@ isc_nm_listenudp(isc_nm_t *mgr, uint32_t workers, isc_sockaddr_t *iface,
sock->children = isc_mem_getx(worker->mctx, children_size, sock->children = isc_mem_getx(worker->mctx, children_size,
ISC_MEM_ZERO); ISC_MEM_ZERO);
isc_barrier_init(&sock->barrier, sock->nchildren); isc__nmsocket_barrier_init(sock);
sock->recv_cb = cb; sock->recv_cb = cb;
sock->recv_cbarg = cbarg; sock->recv_cbarg = cbarg;