2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-26 12:08:05 +00:00
bind/lib/isc/managers.c
Evan Hunt 308bc46a59 Convert dispatch to netmgr
The flow of operations in dispatch is changing and will now be similar
for both UDP and TCP queries:

1) Call dns_dispatch_addresponse() to assign a query ID and register
   that we'll be listening for a response with that ID soon. the
   parameters for this function include callback functions to inform the
   caller when the socket is connected and when the message has been
   sent, as well as a task action that will be sent when the response
   arrives. (later this could become a netmgr callback, but at this
   stage to minimize disruption to the calling code, we continue to use
   isc_task for the response event.) on successful completion of this
   function, a dispatch entry object will be instantiated.

2) Call dns_dispatch_connect() on the dispatch entry. this runs
   isc_nm_udpconnect() or isc_nm_tcpdnsconnect(), as needed, and begins
   listening for responses. the caller is informed via a callback
   function when the connection is established.

3) Call dns_dispatch_send() on the dispatch entry. this runs
   isc_nm_send() to send a request.

4) Call dns_dispatch_removeresponse() to terminate listening and close
   the connection.

Implementation comments below:

- As we will be using netmgr buffers now.  code to send the length in
  TCP queries has also been removed as that is handled by the netmgr.

- TCP dispatches can be used by multiple simultaneous queries, so
  dns_dispatch_connect() now checks whether the dispatch is already
  connected before calling isc_nm_tcpdnsconnect() again.

- Running dns_dispatch_getnext() from a non-network thread caused a
  crash due to assertions in the netmgr read functions that appear to be
  unnecessary now. the assertions have been removed.

- fctx->nqueries was formerly incremented when the connection was
  successful, but is now incremented when the query is started and
  decremented if the connection fails.

- It's no longer necessary for each dispatch to have a pool of tasks, so
  there's now a single task per dispatch.

- Dispatch code to avoid UDP ports already in use has been removed.

- dns_resolver and dns_request have been modified to use netmgr callback
  functions instead of task events. some additional changes were needed
  to handle shutdown processing correctly.

- Timeout processing is not yet fully converted to use netmgr timeouts.

- Fixed a lock order cycle reported by TSAN (view -> zone-> adb -> view)
  by by calling dns_zt functions without holding the view lock.
2021-10-02 11:39:56 -07:00

145 lines
3.6 KiB
C

/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#include <isc/hp.h>
#include <isc/managers.h>
#include <isc/util.h>
#include "netmgr_p.h"
#include "socket_p.h"
#include "task_p.h"
#include "timer_p.h"
isc_result_t
isc_managers_create(isc_mem_t *mctx, size_t workers, size_t quantum,
size_t sockets, isc_nm_t **netmgrp,
isc_taskmgr_t **taskmgrp, isc_timermgr_t **timermgrp,
isc_socketmgr_t **socketmgrp) {
isc_result_t result;
isc_nm_t *netmgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
isc_taskmgr_t *taskmgr = NULL;
isc_timermgr_t *timermgr = NULL;
/*
* We have ncpus network threads, ncpus old network threads - make
* it 4x just to be on the safe side.
*/
isc_hp_init(4 * workers);
REQUIRE(netmgrp != NULL && *netmgrp == NULL);
isc__netmgr_create(mctx, workers, &netmgr);
*netmgrp = netmgr;
INSIST(netmgr != NULL);
REQUIRE(taskmgrp == NULL || *taskmgrp == NULL);
if (taskmgrp != NULL) {
INSIST(netmgr != NULL);
result = isc__taskmgr_create(mctx, quantum, netmgr, &taskmgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_taskmgr_create() failed: %s",
isc_result_totext(result));
goto fail;
}
*taskmgrp = taskmgr;
}
REQUIRE(timermgrp == NULL || *timermgrp == NULL);
if (timermgrp != NULL) {
result = isc__timermgr_create(mctx, &timermgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_timermgr_create() failed: %s",
isc_result_totext(result));
goto fail;
}
*timermgrp = timermgr;
}
REQUIRE(socketmgrp == NULL || *socketmgrp == NULL);
if (socketmgrp != NULL) {
result = isc__socketmgr_create(mctx, &socketmgr, sockets,
workers);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socketmgr_create() failed: %s",
isc_result_totext(result));
goto fail;
}
*socketmgrp = socketmgr;
}
return (ISC_R_SUCCESS);
fail:
isc_managers_destroy(netmgrp, taskmgrp, timermgrp, socketmgrp);
return (result);
}
void
isc_managers_destroy(isc_nm_t **netmgrp, isc_taskmgr_t **taskmgrp,
isc_timermgr_t **timermgrp, isc_socketmgr_t **socketmgrp) {
/*
* If we have a taskmgr to clean up, then we must also have a netmgr.
*/
REQUIRE(taskmgrp == NULL || netmgrp != NULL);
/*
* The sequence of operations here is important:
*
* 1. Initiate shutdown of the taskmgr, sending shutdown events to
* all tasks that are not already shutting down.
*/
if (taskmgrp != NULL) {
INSIST(*taskmgrp != NULL);
isc__taskmgr_shutdown(*taskmgrp);
}
/*
* 2. Initiate shutdown of the network manager, freeing clients
* and other resources and preventing new connections, but do
* not stop processing of existing events.
*/
if (netmgrp != NULL) {
INSIST(*netmgrp != NULL);
isc__netmgr_shutdown(*netmgrp);
}
/*
* 3. Finish destruction of the task manager when all tasks
* have completed.
*/
if (taskmgrp != NULL) {
isc__taskmgr_destroy(taskmgrp);
}
/*
* 4. Finish destruction of the netmgr, and wait until all
* references have been released.
*/
if (netmgrp != NULL) {
isc__netmgr_destroy(netmgrp);
}
/*
* 5. Clean up the remaining managers.
*/
if (timermgrp != NULL) {
INSIST(*timermgrp != NULL);
isc__timermgr_destroy(timermgrp);
}
if (socketmgrp != NULL) {
INSIST(*socketmgrp != NULL);
isc__socketmgr_destroy(socketmgrp);
}
}