Skip to content

Commit c5890d6

Browse files
count the number of allocated frames; the next task is to implement the new tx spool
1 parent d6a6465 commit c5890d6

File tree

3 files changed

+18
-14
lines changed

3 files changed

+18
-14
lines changed

.idea/dictionaries/project.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libudpard/udpard.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ typedef struct tx_frame_t
496496
{
497497
size_t refcount;
498498
udpard_mem_deleter_t deleter;
499+
size_t* objcount;
499500
struct tx_frame_t* next;
500501
size_t size;
501502
byte_t data[];
@@ -511,14 +512,17 @@ static tx_frame_t* tx_frame_from_view(const udpard_bytes_t view)
511512
return (tx_frame_t*)unbias_ptr(view.data, offsetof(tx_frame_t, data));
512513
}
513514

514-
static tx_frame_t* tx_frame_new(const udpard_mem_resource_t mem, const size_t data_size)
515+
static tx_frame_t* tx_frame_new(udpard_tx_t* const tx, const udpard_mem_resource_t mem, const size_t data_size)
515516
{
516517
tx_frame_t* const frame = (tx_frame_t*)mem_alloc(mem, sizeof(tx_frame_t) + data_size);
517518
if (frame != NULL) {
518519
frame->refcount = 1U;
519520
frame->deleter = (udpard_mem_deleter_t){ .user = mem.user, .free = mem.free };
521+
frame->objcount = &tx->enqueued_frames_count;
520522
frame->next = NULL;
521523
frame->size = data_size;
524+
// Update the count; this is decremented when the frame is freed upon refcount reaching zero.
525+
tx->enqueued_frames_count++;
522526
}
523527
return frame;
524528
}
@@ -623,7 +627,7 @@ static bool tx_ensure_queue_space(udpard_tx_t* const tx, const size_t total_fram
623627
while (total_frames_needed > (tx->enqueued_frames_limit - tx->enqueued_frames_count)) {
624628
tx_transfer_t* const victim = tx_sacrifice(tx);
625629
if (victim == NULL) {
626-
break;
630+
break; // We may have no transfers anymore but the NIC TX driver could still be holding some frames.
627631
}
628632
tx_transfer_free(tx, victim);
629633
}
@@ -666,10 +670,7 @@ static udpard_tx_feedback_t tx_make_feedback(const tx_transfer_t* const tr, cons
666670
}
667671

668672
/// Returns the head of the transfer chain; NULL on OOM.
669-
static tx_frame_t* tx_spool(const udpard_mem_resource_t memory,
670-
const size_t mtu,
671-
const meta_t meta,
672-
const udpard_bytes_t payload)
673+
static tx_frame_t* tx_spool(udpard_tx_t* const tx, const size_t mtu, const meta_t meta, const udpard_bytes_t payload)
673674
{
674675
UDPARD_ASSERT(mtu > 0);
675676
UDPARD_ASSERT((payload.data != NULL) || (payload.size == 0U));
@@ -684,7 +685,7 @@ static tx_frame_t* tx_spool(const udpard_mem_resource_t memory,
684685
// Compute the size of the next frame, allocate it and link it up in the chain.
685686
const size_t progress = smaller(payload.size - offset, mtu);
686687
{
687-
tx_frame_t* const item = tx_frame_new(memory, progress);
688+
tx_frame_t* const item = tx_frame_new(tx, tx->memory, progress);
688689
if (NULL == head) {
689690
head = item;
690691
} else {
@@ -696,7 +697,7 @@ static tx_frame_t* tx_spool(const udpard_mem_resource_t memory,
696697
if (NULL == tail) {
697698
while (head != NULL) {
698699
tx_frame_t* const next = head->next;
699-
mem_free(memory, sizeof(tx_frame_t) + head->size, head);
700+
mem_free(tx->memory, sizeof(tx_frame_t) + head->size, head);
700701
head = next;
701702
}
702703
break;
@@ -755,7 +756,7 @@ static uint32_t tx_push(udpard_tx_t* const tx,
755756
tr->feedback = feedback;
756757
tr->staged_until =
757758
meta.flag_ack ? (now + tx_ack_timeout(tx->ack_baseline_timeout, tr->priority, tr->epoch)) : HEAT_DEATH;
758-
tr->head = tr->cursor = tx_spool(tx->memory, mtu, meta, payload);
759+
tr->head = tr->cursor = tx_spool(tx, mtu, meta, payload);
759760
if (tr->head != NULL) {
760761
for (uint_fast8_t i = 0; i < UDPARD_IFACE_COUNT_MAX; i++) {
761762
if (udpard_is_valid_endpoint(tr->destination[i])) {
@@ -781,7 +782,6 @@ static uint32_t tx_push(udpard_tx_t* const tx,
781782
&tr->index_deadline,
782783
cavl2_trivial_factory);
783784
enlist_head(&tx->agewise, &tr->agewise);
784-
tx->enqueued_frames_count += n_frames;
785785
UDPARD_ASSERT(tx->enqueued_frames_count <= tx->enqueued_frames_limit);
786786
out = (uint32_t)n_frames;
787787
} else { // The queue is large enough but we ran out of heap memory.
@@ -1012,7 +1012,6 @@ static void tx_eject_pending(udpard_tx_t* const self, const udpard_us_t now, con
10121012
UDPARD_ASSERT(tr->head == tr->cursor); // They go together on the last attempt.
10131013
tr->head[ifindex] = frame_next;
10141014
udpard_tx_refcount_dec(ejection.datagram);
1015-
self->enqueued_frames_count--;
10161015
}
10171016
tr->cursor[ifindex] = frame_next;
10181017

@@ -1057,6 +1056,7 @@ void udpard_tx_refcount_dec(const udpard_bytes_t tx_payload_view)
10571056
UDPARD_ASSERT(frame->refcount > 0); // NOLINT(*ArrayBound)
10581057
frame->refcount--;
10591058
if (frame->refcount == 0U) {
1059+
--*frame->objcount;
10601060
frame->deleter.free(frame->deleter.user, sizeof(tx_frame_t) + tx_payload_view.size, frame);
10611061
}
10621062
}

libudpard/udpard.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ typedef struct udpard_tx_mem_resources_t
282282
udpard_mem_resource_t transfer;
283283

284284
/// The UDP datagram payload buffers are allocated per frame; each buffer is of size at most
285-
/// (HEADER_SIZE+MTU+sizeof(void*)) bytes, so a trivial block pool is enough if MTU is known in advance.
285+
/// HEADER_SIZE + MTU + small overhead, so a trivial block pool is enough if MTU is known in advance.
286286
udpard_mem_resource_t payload[UDPARD_IFACE_COUNT_MAX];
287287
} udpard_tx_mem_resources_t;
288288

@@ -345,10 +345,13 @@ struct udpard_tx_t
345345

346346
/// The maximum number of UDP datagrams irrespective of the transfer count, for all ifaces pooled.
347347
/// The purpose of this limitation is to ensure that a blocked interface queue does not exhaust the memory.
348-
/// When the limit is reached, the library will apply simple heuristics to choose which transfers to drop.
348+
/// When the limit is reached, the library will apply simple heuristics to choose which transfers to sacrifice.
349349
size_t enqueued_frames_limit;
350350

351-
/// The number of frames that are currently registered in the queue, initially zero. READ-ONLY!
351+
/// The number of frames that are currently registered in the queue, initially zero.
352+
/// This includes frames that are handed over to the NIC driver for transmission that are not yet released
353+
/// via udpard_tx_refcount_dec().
354+
/// READ-ONLY!
352355
size_t enqueued_frames_count;
353356

354357
udpard_tx_mem_resources_t memory;

0 commit comments

Comments
 (0)