]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Complete the isc_nmhandle_detach() in the worker thread.
authorMark Andrews <marka@isc.org>
Mon, 12 Oct 2020 06:51:09 +0000 (17:51 +1100)
committerMark Andrews <marka@isc.org>
Mon, 12 Oct 2020 06:51:09 +0000 (17:51 +1100)
isc_nmhandle_detach() needs to complete in the same thread
as shutdown_walk_cb() to avoid a race.  Clear the caller's
pointer then pass control to the worker if necessary.

    WARNING: ThreadSanitizer: data race
    Write of size 8 at 0x000000000001 by thread T1:
    #0 isc_nmhandle_detach lib/isc/netmgr/netmgr.c:1258:15
    #1 control_command bin/named/controlconf.c:388:3
    #2 dispatch lib/isc/task.c:1152:7
    #3 run lib/isc/task.c:1344:2

    Previous read of size 8 at 0x000000000001 by thread T2:
    #0 isc_nm_pauseread lib/isc/netmgr/netmgr.c:1449:33
    #1 recv_data lib/isccc/ccmsg.c:109:2
    #2 isc__nm_tcp_shutdown lib/isc/netmgr/tcp.c:1157:4
    #3 shutdown_walk_cb lib/isc/netmgr/netmgr.c:1515:3
    #4 uv_walk <null>
    #5 process_queue lib/isc/netmgr/netmgr.c:659:4
    #6 process_normal_queue lib/isc/netmgr/netmgr.c:582:10
    #7 process_queues lib/isc/netmgr/netmgr.c:590:8
    #8 async_cb lib/isc/netmgr/netmgr.c:548:2
    #9 <null> <null>

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c

index 4d6ef88193084cba23076e3e40f2b36a6aa756d2..b9a9672783891284c13ed2751c6041b33bf3a47b 100644 (file)
@@ -164,6 +164,7 @@ typedef enum isc__netievent_type {
        netievent_udplisten,
        netievent_tcplisten,
        netievent_resume,
+       netievent_detach,
 } isc__netievent_type;
 
 typedef union {
@@ -247,6 +248,8 @@ typedef struct isc__netievent__socket_handle {
        isc_nmhandle_t *handle;
 } isc__netievent__socket_handle_t;
 
+typedef isc__netievent__socket_handle_t isc__netievent_detach_t;
+
 typedef struct isc__netievent__socket_quota {
        isc__netievent_type type;
        isc_nmsocket_t *sock;
index c1eb14005aeca4f10e482d56d7ebc0fcb91f5b81..8358ee4e61a0110de198078bbf9d423381d9860c 100644 (file)
@@ -145,6 +145,11 @@ static void
 isc__nm_async_pausecb(isc__networker_t *worker, isc__netievent_t *ev0);
 static void
 isc__nm_async_resumecb(isc__networker_t *worker, isc__netievent_t *ev0);
+static void
+isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0);
+
+static void
+nmhandle_detach_cb(isc_nmhandle_t **handlep);
 
 int
 isc_nm_tid(void) {
@@ -655,6 +660,9 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
                case netievent_closecb:
                        isc__nm_async_closecb(worker, ievent);
                        break;
+               case netievent_detach:
+                       isc__nm_async_detach(worker, ievent);
+                       break;
                case netievent_shutdown:
                        isc__nm_async_shutdown(worker, ievent);
                        break;
@@ -1247,6 +1255,30 @@ isc_nmhandle_detach(isc_nmhandle_t **handlep) {
        handle = *handlep;
        *handlep = NULL;
 
+       sock = handle->sock;
+       if (sock->tid == isc_nm_tid()) {
+               nmhandle_detach_cb(&handle);
+       } else {
+               isc__netievent_detach_t *event =
+                       isc__nm_get_ievent(sock->mgr, netievent_detach);
+               event->handle = handle; /* implict attach */
+               isc__nmsocket_attach(sock, &event->sock);
+               isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
+                                      (isc__netievent_t *)event);
+       }
+}
+
+static void
+nmhandle_detach_cb(isc_nmhandle_t **handlep) {
+       isc_nmsocket_t *sock = NULL;
+       isc_nmhandle_t *handle = NULL;
+
+       REQUIRE(handlep != NULL);
+       REQUIRE(VALID_NMHANDLE(*handlep));
+
+       handle = *handlep;
+       *handlep = NULL;
+
        if (isc_refcount_decrement(&handle->references) > 1) {
                return;
        }
@@ -1506,6 +1538,20 @@ isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0) {
        isc__nmsocket_detach(&ievent->sock);
 }
 
+void
+isc__nm_async_detach(isc__networker_t *worker, isc__netievent_t *ev0) {
+       isc__netievent_detach_t *ievent = (isc__netievent_detach_t *)ev0;
+
+       REQUIRE(VALID_NMSOCK(ievent->sock));
+       REQUIRE(ievent->sock->tid == isc_nm_tid());
+       REQUIRE(ievent->handle != NULL);
+
+       UNUSED(worker);
+
+       isc__nmsocket_detach(&ievent->sock);
+       nmhandle_detach_cb(&ievent->handle);
+}
+
 static void
 shutdown_walk_cb(uv_handle_t *handle, void *arg) {
        UNUSED(arg);