You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2020/09/03 21:58:02 UTC

[mynewt-nimble] branch master updated: nimble/hs: remove recursive call

This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git


The following commit(s) were added to refs/heads/master by this push:
     new 7c7f61c  nimble/hs: remove recursive call
7c7f61c is described below

commit 7c7f61ca6259ca73fb9e580e1f704120458d0fcd
Author: Simon Schubert <2...@0x2c.org>
AuthorDate: Tue Sep 1 20:19:52 2020 +0200

    nimble/hs: remove recursive call
    
    On esp32, tail call optimization does not exist, which can lead to a
    stack overflow.
---
 nimble/host/src/ble_hs_conn.c | 106 +++++++++++++++++++++---------------------
 1 file changed, 53 insertions(+), 53 deletions(-)

diff --git a/nimble/host/src/ble_hs_conn.c b/nimble/host/src/ble_hs_conn.c
index 70695fa..ea89460 100644
--- a/nimble/host/src/ble_hs_conn.c
+++ b/nimble/host/src/ble_hs_conn.c
@@ -481,29 +481,52 @@ ble_hs_conn_timer(void)
     int32_t time_diff;
     uint16_t conn_handle;
 
-    conn_handle = BLE_HS_CONN_HANDLE_NONE;
-    next_exp_in = BLE_HS_FOREVER;
-    now = ble_npl_time_get();
-
-    ble_hs_lock();
-
-    /* This loop performs one of two tasks:
-     * 1. Determine if any connections need to be terminated due to timeout.
-     *    If so, break out of the loop and terminate the connection.  This
-     *    function will need to be executed again.
-     * 2. Otherwise, determine when the next timeout will occur.
-     */
-    SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
-        if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) {
+    for (;;) {
+        conn_handle = BLE_HS_CONN_HANDLE_NONE;
+        next_exp_in = BLE_HS_FOREVER;
+        now = ble_npl_time_get();
+
+        ble_hs_lock();
+
+        /* This loop performs one of two tasks:
+         * 1. Determine if any connections need to be terminated due to timeout.
+         *    If so, break out of the loop and terminate the connection.  This
+         *    function will need to be executed again.
+         * 2. Otherwise, determine when the next timeout will occur.
+         */
+        SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) {
+            if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) {
 
 #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0
-            /* Check each connection's rx fragment timer.  If too much time
-             * passes after a partial packet is received, the connection is
-             * terminated.
-             */
-            if (conn->bhc_rx_chan != NULL) {
-                time_diff = conn->bhc_rx_timeout - now;
+                /* Check each connection's rx fragment timer.  If too much time
+                 * passes after a partial packet is received, the connection is
+                 * terminated.
+                 */
+                if (conn->bhc_rx_chan != NULL) {
+                    time_diff = conn->bhc_rx_timeout - now;
+
+                    if (time_diff <= 0) {
+                        /* ACL reassembly has timed out.  Remember the connection
+                         * handle so it can be terminated after the mutex is
+                         * unlocked.
+                         */
+                        conn_handle = conn->bhc_handle;
+                        break;
+                    }
+
+                    /* Determine if this connection is the soonest to time out. */
+                    if (time_diff < next_exp_in) {
+                        next_exp_in = time_diff;
+                    }
+                }
+#endif
 
+#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO
+                /* Check each connection's rx queued write timer.  If too much
+                 * time passes after a prep write is received, the queue is
+                 * cleared.
+                 */
+                time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now);
                 if (time_diff <= 0) {
                     /* ACL reassembly has timed out.  Remember the connection
                      * handle so it can be terminated after the mutex is
@@ -517,45 +540,22 @@ ble_hs_conn_timer(void)
                 if (time_diff < next_exp_in) {
                     next_exp_in = time_diff;
                 }
-            }
 #endif
-
-#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO
-            /* Check each connection's rx queued write timer.  If too much
-             * time passes after a prep write is received, the queue is
-             * cleared.
-             */
-            time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now);
-            if (time_diff <= 0) {
-                /* ACL reassembly has timed out.  Remember the connection
-                 * handle so it can be terminated after the mutex is
-                 * unlocked.
-                 */
-                conn_handle = conn->bhc_handle;
-                break;
             }
-
-            /* Determine if this connection is the soonest to time out. */
-            if (time_diff < next_exp_in) {
-                next_exp_in = time_diff;
-            }
-#endif
         }
-    }
 
-    ble_hs_unlock();
+        ble_hs_unlock();
 
-    /* If a connection has timed out, terminate it.  We need to recursively
-     * call this function again to determine when the next timeout is.  This
-     * is a tail-recursive call, so it should be optimized to execute in the
-     * same stack frame.
-     */
-    if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
-        ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
-        return ble_hs_conn_timer();
-    }
+        /* If a connection has timed out, terminate it.  We need to repeatedly
+         * call this function again to determine when the next timeout is.
+         */
+        if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
+            ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
+            continue;
+        }
 
-    return next_exp_in;
+        return next_exp_in;
+    }
 }
 
 int