Skip to content

Commit

Permalink
Bluetooth: Mesh: transport: update delayable work
Browse files Browse the repository at this point in the history
Switch to the new API. Adds early exits for the ack and retransmit
timers, and replaces a remaining_time() + submit() call with schedule().

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
  • Loading branch information
pabigot authored and jhedberg committed Apr 28, 2021
1 parent 1577fec commit 4e6cb11
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions subsys/bluetooth/mesh/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static struct seg_tx {
friend_cred:1; /* Using Friend credentials */
const struct bt_mesh_send_cb *cb;
void *cb_data;
struct k_delayed_work retransmit; /* Retransmit timer */
struct k_work_delayable retransmit; /* Retransmit timer */
} seg_tx[CONFIG_BT_MESH_TX_SEG_MSG_COUNT];

static struct seg_rx {
Expand All @@ -133,7 +133,7 @@ static struct seg_rx {
uint8_t ttl;
uint32_t block;
uint32_t last;
struct k_delayed_work ack;
struct k_work_delayable ack;
} seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT];

K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
Expand Down Expand Up @@ -247,15 +247,16 @@ static void seg_tx_unblock_check(struct seg_tx *tx)
BT_DBG("Unblocked 0x%04x",
(uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK));
blocked->blocked = false;
k_delayed_work_submit(&blocked->retransmit, K_NO_WAIT);
k_work_reschedule(&blocked->retransmit, K_NO_WAIT);
}
}

static void seg_tx_reset(struct seg_tx *tx)
{
int i;

k_delayed_work_cancel(&tx->retransmit);
/* If this call fails, the handler will exit early, as nack_count is 0. */
(void)k_work_cancel_delayable(&tx->retransmit);

tx->cb = NULL;
tx->cb_data = NULL;
Expand Down Expand Up @@ -315,9 +316,9 @@ static void schedule_retransmit(struct seg_tx *tx)
* called this from inside bt_mesh_net_send), we should continue the
* retransmit immediately, as we just freed up a tx buffer.
*/
k_delayed_work_submit(&tx->retransmit,
tx->seg_o ? K_NO_WAIT :
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
k_work_reschedule(&tx->retransmit,
tx->seg_o ? K_NO_WAIT :
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
}

static void seg_send_start(uint16_t duration, int err, void *user_data)
Expand Down Expand Up @@ -440,8 +441,8 @@ static void seg_tx_send_unacked(struct seg_tx *tx)

end:
if (!tx->seg_pending) {
k_delayed_work_submit(&tx->retransmit,
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
k_work_reschedule(&tx->retransmit,
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
}

tx->sending = 0U;
Expand Down Expand Up @@ -859,8 +860,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
return -EINVAL;
}

k_delayed_work_cancel(&tx->retransmit);

while ((bit = find_lsb_set(ack))) {
if (tx->seg[bit - 1]) {
BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n);
Expand All @@ -871,7 +870,11 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
}

if (tx->nack_count) {
seg_tx_send_unacked(tx);
/* According to the Bluetooth Mesh Profile specification,
* section 3.5.3.3, we should reset the retransmit timer and
* retransmit immediately when receiving a valid ack message:
*/
k_work_reschedule(&tx->retransmit, K_NO_WAIT);
} else {
BT_DBG("SDU TX complete");
seg_tx_complete(tx, 0);
Expand Down Expand Up @@ -1090,7 +1093,10 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset)

BT_DBG("rx %p", rx);

k_delayed_work_cancel(&rx->ack);
/* If this fails, the handler will exit early on the next execution, as
* it checks rx->in_use.
*/
(void)k_work_cancel_delayable(&rx->ack);

if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo &&
rx->block != BLOCK_COMPLETE(rx->seg_n)) {
Expand Down Expand Up @@ -1127,6 +1133,16 @@ static void seg_ack(struct k_work *work)
struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack);
int32_t timeout;

if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) {
/* Cancellation of this timer may have failed. If it fails as
* part of seg_reset, in_use will be false.
* If it fails as part of the processing of a fully received
* SDU, the ack is already being sent from the receive handler,
* and the timer based ack sending can be ignored.
*/
return;
}

BT_DBG("rx %p", rx);

if (k_uptime_get_32() - rx->last > (60 * MSEC_PER_SEC)) {
Expand All @@ -1144,7 +1160,7 @@ static void seg_ack(struct k_work *work)
rx->block, rx->obo);

timeout = ack_timeout(rx);
k_delayed_work_submit(&rx->ack, K_MSEC(timeout));
k_work_schedule(&rx->ack, K_MSEC(timeout));
}

static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n)
Expand Down Expand Up @@ -1447,11 +1463,10 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx,
/* Reset the Incomplete Timer */
rx->last = k_uptime_get_32();

if (!k_delayed_work_remaining_get(&rx->ack) &&
!bt_mesh_lpn_established()) {
if (!bt_mesh_lpn_established()) {
int32_t timeout = ack_timeout(rx);

k_delayed_work_submit(&rx->ack, K_MSEC(timeout));
/* Should only start ack timer if it isn't running already: */
k_work_schedule(&rx->ack, K_MSEC(timeout));
}

/* Allocated segment here */
Expand Down Expand Up @@ -1487,7 +1502,10 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx,

*pdu_type = BT_MESH_FRIEND_PDU_COMPLETE;

k_delayed_work_cancel(&rx->ack);
/* If this fails, the work handler will either exit early because the
* block is fully received, or rx->in_use is false.
*/
(void)k_work_cancel_delayable(&rx->ack);
send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr,
net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo);

Expand Down Expand Up @@ -1643,11 +1661,11 @@ void bt_mesh_trans_init(void)
int i;

for (i = 0; i < ARRAY_SIZE(seg_tx); i++) {
k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit);
k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit);
}

for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
k_delayed_work_init(&seg_rx[i].ack, seg_ack);
k_work_init_delayable(&seg_rx[i].ack, seg_ack);
}
}

Expand Down

0 comments on commit 4e6cb11

Please sign in to comment.