asfgit closed pull request #427: DISPATCH-1226: fix race during link detach 
handling
URL: https://github.com/apache/qpid-dispatch/pull/427
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/src/router_core/connections.c b/src/router_core/connections.c
index d6ced984..a528d261 100644
--- a/src/router_core/connections.c
+++ b/src/router_core/connections.c
@@ -32,7 +32,8 @@ static void qdr_connection_closed_CT(qdr_core_t *core, 
qdr_action_t *action, boo
 static void qdr_link_inbound_first_attach_CT(qdr_core_t *core, qdr_action_t 
*action, bool discard);
 static void qdr_link_inbound_second_attach_CT(qdr_core_t *core, qdr_action_t 
*action, bool discard);
 static void qdr_link_inbound_detach_CT(qdr_core_t *core, qdr_action_t *action, 
bool discard);
-static void qdr_link_delete_CT(qdr_core_t *core, qdr_action_t *action, bool 
discard);
+static void qdr_link_detach_sent_CT(qdr_core_t *core, qdr_action_t *action, 
bool discard);
+static void qdr_link_detach_sent(qdr_link_t *link);
 
 ALLOC_DEFINE(qdr_connection_t);
 ALLOC_DEFINE(qdr_connection_work_t);
@@ -215,7 +216,7 @@ int qdr_connection_process(qdr_connection_t *conn)
 
     qdr_link_ref_t *ref;
     qdr_link_t     *link;
-    bool            free_link;
+    bool            detach_sent;
 
     int event_count = 0;
 
@@ -262,7 +263,7 @@ int qdr_connection_process(qdr_connection_t *conn)
     for (int priority = QDR_MAX_PRIORITY; priority >= 0; -- priority) {
         do {
             qdr_link_work_t *link_work;
-            free_link = false;
+            detach_sent = false;
 
             ref = DEQ_HEAD(links_with_work[priority]);
             if (ref) {
@@ -323,12 +324,11 @@ int qdr_connection_process(qdr_connection_t *conn)
                         break;
 
                     case QDR_LINK_WORK_FIRST_DETACH :
-                        core->detach_handler(core->user_context, link, 
link_work->error, true, link_work->close_link);
-                        break;
-
                     case QDR_LINK_WORK_SECOND_DETACH :
-                        core->detach_handler(core->user_context, link, 
link_work->error, false, link_work->close_link);
-                        free_link = true;
+                        core->detach_handler(core->user_context, link, 
link_work->error,
+                                             link_work->work_type == 
QDR_LINK_WORK_FIRST_DETACH,
+                                             link_work->close_link);
+                        detach_sent = true;
                         break;
                     }
 
@@ -350,10 +350,12 @@ int qdr_connection_process(qdr_connection_t *conn)
                     event_count++;
                 }
 
-                if (free_link)
-                    qdr_link_delete(link);
+                if (detach_sent) {
+                    // let the core thread know so it can clean up
+                    qdr_link_detach_sent(link);
+                }
             }
-        } while (free_link || link);
+        } while (detach_sent || link);
     }
 
     return event_count;
@@ -526,9 +528,11 @@ void qdr_link_detach(qdr_link_t *link, qd_detach_type_t 
dt, qdr_error_t *error)
 }
 
 
-void qdr_link_delete(qdr_link_t *link)
+/* let the core thread know that a dispatch has been sent by the I/O thread
+ */
+static void qdr_link_detach_sent(qdr_link_t *link)
 {
-    qdr_action_t *action = qdr_action(qdr_link_delete_CT, "link_delete");
+    qdr_action_t *action = qdr_action(qdr_link_detach_sent_CT, 
"link_detach_sent");
 
     action->args.connection.link = link;
     qdr_action_enqueue(link->core, action);
@@ -909,9 +913,6 @@ void qdr_link_outbound_detach_CT(qdr_core_t *core, 
qdr_link_t *link, qdr_error_t
     qdr_link_work_t *work = new_qdr_link_work_t();
     ZERO(work);
     work->work_type  = ++link->detach_count == 1 ? QDR_LINK_WORK_FIRST_DETACH 
: QDR_LINK_WORK_SECOND_DETACH;
-    if (work->work_type == QDR_LINK_WORK_SECOND_DETACH) {
-        link->detach_received = true;
-    }
     work->close_link = close;
 
     if (error)
@@ -1536,10 +1537,11 @@ static void qdr_link_inbound_detach_CT(qdr_core_t 
*core, qdr_action_t *action, b
     qd_detach_type_t  dt    = action->args.connection.dt;
     qdr_address_t    *addr  = link->owning_addr;
 
-    //
-    // Bump the detach count to track half and full detaches
-    //
-    link->detach_count++;
+    if (link->detach_received)
+        return;
+
+    link->detach_received = true;
+    ++link->detach_count;
 
     if (link->core_endpoint) {
         qdrc_endpoint_do_detach_CT(core, link->core_endpoint, error);
@@ -1568,7 +1570,7 @@ static void qdr_link_inbound_detach_CT(qdr_core_t *core, 
qdr_action_t *action, b
             //
             // If the link is completely detached, release its resources
             //
-            if (link->detach_count == 2) {
+            if (link->detach_send_done) {
                 qdr_link_cleanup_CT(core, conn, link);
                 free_qdr_link_t(link);
             }
@@ -1655,13 +1657,19 @@ static void qdr_link_inbound_detach_CT(qdr_core_t 
*core, qdr_action_t *action, b
         // Handle the disposition of any deliveries that remain on the link
         //
         qdr_link_cleanup_deliveries_CT(core, conn, link);
-        
+
         //
         // If the detach occurred via protocol, send a detach back.
         //
-        if (dt != QD_LOST)
+        if (dt != QD_LOST) {
             qdr_link_outbound_detach_CT(core, link, 0, QDR_CONDITION_NONE, dt 
== QD_CLOSED);
-    } else {
+        } else {
+            // no detach can be sent out because the connection was lost
+            qdr_link_cleanup_CT(core, conn, link);
+            free_qdr_link_t(link);
+        }
+    } else if (link->detach_send_done) {  // detach count indicates detach has 
been scheduled
+        // I/O thread is finished sending detach, ok to free link now
         qdr_link_cleanup_CT(core, conn, link);
         free_qdr_link_t(link);
     }
@@ -1678,16 +1686,22 @@ static void qdr_link_inbound_detach_CT(qdr_core_t 
*core, qdr_action_t *action, b
 }
 
 
-static void qdr_link_delete_CT(qdr_core_t *core, qdr_action_t *action, bool 
discard)
+/* invoked on core thread to signal that the I/O thread has sent the detach
+ */
+static void qdr_link_detach_sent_CT(qdr_core_t *core, qdr_action_t *action, 
bool discard)
 {
     if (discard)
         return;
 
     qdr_link_t *link = action->args.connection.link;
 
-    if (link && link->conn) {
-        qdr_link_cleanup_CT(core, link->conn, link);
-        free_qdr_link_t(link);
+    if (link) {
+        link->detach_send_done = true;
+        if (link->conn && link->detach_received) {
+            // link is fully detached
+            qdr_link_cleanup_CT(core, link->conn, link);
+            free_qdr_link_t(link);
+        }
     }
 }
 
diff --git a/src/router_core/router_core_private.h 
b/src/router_core/router_core_private.h
index a2ebc8e4..6695527a 100644
--- a/src/router_core/router_core_private.h
+++ b/src/router_core/router_core_private.h
@@ -441,7 +441,8 @@ struct qdr_link_t {
     bool                     strip_annotations_out;
     bool                     drain_mode;
     bool                     stalled_outbound;  ///< Indicates that this link 
is stalled on outbound buffer backpressure
-    bool                     detach_received;
+    bool                     detach_received;   ///< True on core receipt of 
inbound attach
+    bool                     detach_send_done;  ///< True once the detach has 
been sent by the I/O thread
     bool                     edge;              ///< True if this link is in 
an edge-connection
     char                    *strip_prefix;
     char                    *insert_prefix;


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to