Skip to content

Commit c6113b9

Browse files
udpard_tx_pending_iface_mask
1 parent a5f211f commit c6113b9

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

libudpard/udpard.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,24 @@ void udpard_tx_poll(udpard_tx_t* const self, const udpard_us_t now, const uint32
13011301
}
13021302
}
13031303

1304+
uint32_t udpard_tx_pending_iface_mask(const udpard_tx_t* const self)
1305+
{
1306+
uint32_t mask = 0;
1307+
if (self != NULL) {
1308+
// Even though it's constant-time, I still mildly dislike this loop. Shall it become a bottleneck,
1309+
// we could modify the TX state to keep a mask of pending interfaces updated incrementally.
1310+
for (size_t i = 0; i < UDPARD_IFACE_COUNT_MAX; i++) {
1311+
for (size_t p = 0; p < UDPARD_PRIORITY_COUNT; p++) {
1312+
if (self->queue[i][p].head != NULL) {
1313+
mask |= (1U << i);
1314+
break;
1315+
}
1316+
}
1317+
}
1318+
}
1319+
return mask;
1320+
}
1321+
13041322
void udpard_tx_refcount_inc(const udpard_bytes_t tx_payload_view)
13051323
{
13061324
if (tx_payload_view.data != NULL) {

libudpard/udpard.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,11 @@ uint32_t udpard_tx_push_p2p(udpard_tx_t* const self,
540540
/// The function may deallocate memory. The time complexity is logarithmic in the number of enqueued transfers.
541541
void udpard_tx_poll(udpard_tx_t* const self, const udpard_us_t now, const uint32_t iface_mask);
542542

543+
/// Returns a bitmask of interfaces that have pending transmissions. This is useful for IO multiplexing loops.
544+
/// Zero indicates that there are no pending transmissions.
545+
/// Which interfaces are usable is defined by the remote endpoints provided when pushing transfers.
546+
uint32_t udpard_tx_pending_iface_mask(const udpard_tx_t* const self);
547+
543548
/// When a datagram is ejected and the application opts to keep it, these functions must be used to manage the
544549
/// datagram buffer lifetime. The datagram will be freed once the reference count reaches zero.
545550
void udpard_tx_refcount_inc(const udpard_bytes_t tx_payload_view);

tests/src/test_intrusive_tx.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,11 @@ static void test_tx_ack_and_scheduler(void)
375375
make_scattered(NULL, 0),
376376
record_feedback,
377377
make_user_context(&fstate)));
378+
TEST_ASSERT_EQUAL_UINT32(1U << 0U, udpard_tx_pending_iface_mask(&tx1));
378379
udpard_rx_t rx = { .tx = &tx1 };
379380
tx_receive_ack(&rx, 21, 42);
380381
TEST_ASSERT_EQUAL_size_t(1, fstate.count);
382+
TEST_ASSERT_EQUAL_UINT32(0U, udpard_tx_pending_iface_mask(&tx1));
381383
udpard_tx_free(&tx1);
382384

383385
// Ack suppressed when coverage not improved.
@@ -397,6 +399,7 @@ static void test_tx_ack_and_scheduler(void)
397399
rx.tx = &tx2;
398400
tx_send_ack(&rx, 0, udpard_prio_fast, 7, 8, (udpard_remote_t){ .uid = 9, .endpoints = { make_ep(3) } });
399401
TEST_ASSERT_EQUAL_UINT64(0, rx.errors_ack_tx);
402+
TEST_ASSERT_EQUAL_UINT32(0U, udpard_tx_pending_iface_mask(&tx2));
400403
udpard_tx_free(&tx2);
401404

402405
// Ack replaced with broader coverage.
@@ -406,6 +409,7 @@ static void test_tx_ack_and_scheduler(void)
406409
tx_send_ack(&rx, 0, udpard_prio_fast, 9, 9, (udpard_remote_t){ .uid = 11, .endpoints = { make_ep(4) } });
407410
tx_send_ack(
408411
&rx, 0, udpard_prio_fast, 9, 9, (udpard_remote_t){ .uid = 11, .endpoints = { make_ep(4), make_ep(5) } });
412+
TEST_ASSERT_NOT_EQUAL(0U, udpard_tx_pending_iface_mask(&tx3));
409413
udpard_tx_free(&tx3);
410414

411415
// Ack push failure with TX present.
@@ -466,6 +470,7 @@ static void test_tx_ack_and_scheduler(void)
466470
tx5.ack_baseline_timeout = 1;
467471
tx_promote_staged_transfers(&tx5, 1);
468472
TEST_ASSERT_NOT_NULL(tx5.queue[0][staged.priority].head);
473+
TEST_ASSERT_EQUAL_UINT32(1U << 0U, udpard_tx_pending_iface_mask(&tx5));
469474

470475
// Ejection stops when NIC refuses.
471476
staged.cursor[0] = staged.head[0];
@@ -535,7 +540,7 @@ static void test_tx_stage_if_via_tx_push(void)
535540
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 30U, 1U, 4U, mem, &vt));
536541
tx.user = &log;
537542
tx.ack_baseline_timeout = 10;
538-
udpard_udpip_ep_t dest[UDPARD_IFACE_COUNT_MAX] = { make_ep(1), { 0 } };
543+
udpard_udpip_ep_t dest[UDPARD_IFACE_COUNT_MAX] = { make_ep(1), make_ep(2), { 0 } };
539544

540545
TEST_ASSERT_GREATER_THAN_UINT32(0,
541546
udpard_tx_push(&tx,
@@ -548,14 +553,18 @@ static void test_tx_stage_if_via_tx_push(void)
548553
make_scattered(NULL, 0),
549554
record_feedback,
550555
make_user_context(&fb)));
556+
TEST_ASSERT_EQUAL_UINT32((1U << 0U) | (1U << 1U), udpard_tx_pending_iface_mask(&tx));
551557

552558
udpard_tx_poll(&tx, 0, UDPARD_IFACE_MASK_ALL);
553559
udpard_tx_poll(&tx, 160, UDPARD_IFACE_MASK_ALL);
554560
udpard_tx_poll(&tx, 400, UDPARD_IFACE_MASK_ALL);
561+
TEST_ASSERT_EQUAL_UINT32(0U, udpard_tx_pending_iface_mask(&tx));
555562

556-
TEST_ASSERT_EQUAL_size_t(2, log.count);
563+
TEST_ASSERT_EQUAL_size_t(4, log.count);
557564
TEST_ASSERT_EQUAL(0, log.when[0]);
558-
TEST_ASSERT_EQUAL(160, log.when[1]);
565+
TEST_ASSERT_EQUAL(0, log.when[1]);
566+
TEST_ASSERT_EQUAL(160, log.when[2]);
567+
TEST_ASSERT_EQUAL(160, log.when[3]);
559568
TEST_ASSERT_NULL(tx.index_staged);
560569
udpard_tx_free(&tx);
561570
instrumented_allocator_reset(&alloc);

0 commit comments

Comments
 (0)