@@ -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 }
0 commit comments