3030// --------------------------------------------- COMMONS ---------------------------------------------
3131
3232#define CAVL2_T udpard_tree_t
33- #define CAVL2_RELATION int64_t
33+ #define CAVL2_RELATION int32_t
3434#define CAVL2_ASSERT (x ) UDPARD_ASSERT(x) // NOSONAR
3535#include "cavl2.h"
3636
@@ -284,15 +284,18 @@ static bool tx_validate_mem_resources(const udpard_tx_mem_resources_t memory)
284284}
285285
286286/// Frames with identical weight are processed in the FIFO order.
287- /// Frames with higher weight compare smaller (i.e., put on the left side of the tree).
288- static int64_t tx_cavl_compare_prio (const void * const user , const udpard_tree_t * const node )
287+ static int32_t tx_cavl_compare_prio (const void * const user , const udpard_tree_t * const node )
289288{
290- return ((int )* (const udpard_prio_t * )user ) - (int )(CAVL2_TO_OWNER (node , udpard_tx_item_t , index_prio )-> priority );
289+ return (((int )* (const udpard_prio_t * )user ) >= (int )CAVL2_TO_OWNER (node , udpard_tx_item_t , index_prio )-> priority )
290+ ? +1
291+ : -1 ;
291292}
292293
293- static int64_t tx_cavl_compare_deadline (const void * const user , const udpard_tree_t * const node )
294+ static int32_t tx_cavl_compare_deadline (const void * const user , const udpard_tree_t * const node )
294295{
295- return (* (const udpard_microsecond_t * )user ) - (CAVL2_TO_OWNER (node , udpard_tx_item_t , index_deadline )-> deadline );
296+ return ((* (const udpard_microsecond_t * )user ) >= CAVL2_TO_OWNER (node , udpard_tx_item_t , index_deadline )-> deadline )
297+ ? +1
298+ : -1 ;
296299}
297300
298301static udpard_tx_item_t * tx_item_new (const udpard_tx_mem_resources_t memory ,
@@ -328,7 +331,7 @@ static udpard_tx_item_t* tx_item_new(const udpard_tx_mem_resources_t memory,
328331/// The caller is responsible for freeing the memory allocated for the chain.
329332static tx_chain_t tx_spool (const udpard_tx_mem_resources_t memory ,
330333 const size_t mtu ,
331- const udpard_microsecond_t deadline_usec ,
334+ const udpard_microsecond_t deadline ,
332335 const meta_t meta ,
333336 const udpard_udpip_ep_t endpoint ,
334337 const udpard_bytes_t payload ,
@@ -343,7 +346,7 @@ static tx_chain_t tx_spool(const udpard_tx_mem_resources_t memory,
343346 size_t offset = 0U ;
344347 while (offset < payload_size_with_crc ) {
345348 udpard_tx_item_t * const item = tx_item_new (memory ,
346- deadline_usec ,
349+ deadline ,
347350 meta .priority ,
348351 endpoint ,
349352 smaller (payload_size_with_crc - offset , mtu ) + HEADER_SIZE_BYTES ,
@@ -400,28 +403,22 @@ static uint32_t tx_push(udpard_tx_t* const tx,
400403 tx -> errors_capacity ++ ;
401404 } else {
402405 const tx_chain_t chain = tx_spool (tx -> memory , mtu , deadline , meta , endpoint , payload , user_transfer_reference );
403- if (chain .tail != NULL ) { // Insert every item into the tx indexes.
406+ if (chain .tail != NULL ) { // Insert the head into the tx index. Only the head, the rest is linked-listed.
407+ udpard_tx_item_t * const head = chain .head ;
404408 UDPARD_ASSERT (frame_count == chain .count );
405- udpard_tx_item_t * next = chain .head ;
406- do {
407- const udpard_tree_t * res = cavl2_find_or_insert (& tx -> index_prio , //
408- & next -> priority ,
409- & tx_cavl_compare_prio ,
410- & next -> index_prio ,
411- & cavl2_trivial_factory );
412- UDPARD_ASSERT (res == & next -> index_prio );
413- res = cavl2_find_or_insert (& tx -> index_deadline , //
414- & next -> deadline ,
415- & tx_cavl_compare_deadline ,
416- & next -> index_deadline ,
417- & cavl2_trivial_factory );
418- UDPARD_ASSERT (res == & next -> index_deadline );
419- (void )res ;
420- next = next -> next_in_transfer ;
421- } while (next != NULL );
409+ const udpard_tree_t * res = cavl2_find_or_insert (
410+ & tx -> index_prio , & head -> priority , & tx_cavl_compare_prio , & head -> index_prio , & cavl2_trivial_factory );
411+ UDPARD_ASSERT (res == & head -> index_prio );
412+ (void )res ;
413+ res = cavl2_find_or_insert (& tx -> index_deadline ,
414+ & head -> deadline ,
415+ & tx_cavl_compare_deadline ,
416+ & head -> index_deadline ,
417+ & cavl2_trivial_factory );
418+ UDPARD_ASSERT (res == & head -> index_deadline );
419+ (void )res ;
422420 tx -> queue_size += chain .count ;
423421 UDPARD_ASSERT (tx -> queue_size <= tx -> queue_capacity );
424- UDPARD_ASSERT ((chain .count + 0ULL ) <= INT32_MAX ); // +0 is to suppress warning.
425422 out = (uint32_t )chain .count ;
426423 } else { // The queue is large enough but we ran out of heap memory, so we have to unwind the chain.
427424 tx -> errors_oom ++ ;
@@ -436,6 +433,30 @@ static uint32_t tx_push(udpard_tx_t* const tx,
436433 return out ;
437434}
438435
436+ static uint64_t tx_purge_expired (udpard_tx_t * const self , const udpard_microsecond_t now )
437+ {
438+ uint64_t count = 0 ;
439+ for (udpard_tree_t * p = cavl2_min (self -> index_deadline ); p != NULL ; p = cavl2_next_greater (p )) {
440+ udpard_tx_item_t * const item = CAVL2_TO_OWNER (p , udpard_tx_item_t , index_deadline );
441+ if (item -> deadline >= now ) {
442+ break ;
443+ }
444+ // Remove from both indices.
445+ cavl2_remove (& self -> index_deadline , & item -> index_deadline );
446+ cavl2_remove (& self -> index_prio , & item -> index_prio );
447+ // Free the entire transfer chain.
448+ udpard_tx_item_t * current = item ;
449+ while (current != NULL ) {
450+ udpard_tx_item_t * const next = current -> next_in_transfer ;
451+ udpard_tx_free (self -> memory , current );
452+ current = next ;
453+ count ++ ;
454+ self -> queue_size -- ;
455+ }
456+ }
457+ return count ;
458+ }
459+
439460bool udpard_tx_new (udpard_tx_t * const self ,
440461 const uint64_t local_uid ,
441462 const size_t queue_capacity ,
@@ -463,19 +484,24 @@ uint32_t udpard_tx_publish(udpard_tx_t* const self,
463484 const uint32_t subject_id ,
464485 const uint64_t transfer_id ,
465486 const udpard_bytes_t payload ,
487+ const bool ack_required ,
466488 void * const user_transfer_reference )
467489{
468- (void )self ;
469- (void )now ;
470- (void )deadline ;
471- (void )priority ;
472- (void )topic_hash ;
473- (void )subject_id ;
474- (void )transfer_id ;
475- (void )payload ;
476- (void )user_transfer_reference ;
477- (void )tx_push ;
478- return 0 ;
490+ uint32_t out = 0 ;
491+ if ((self != NULL ) && (self -> local_uid != 0 ) && (priority <= UDPARD_PRIORITY_MAX ) &&
492+ ((payload .data != NULL ) || (payload .size == 0U ))) {
493+ self -> errors_expiration += tx_purge_expired (self , now );
494+ const meta_t meta = {
495+ .priority = priority ,
496+ .flag_ack = ack_required ,
497+ .transfer_payload_size = (uint32_t )payload .size ,
498+ .transfer_id = transfer_id ,
499+ .sender_uid = self -> local_uid ,
500+ .topic_hash = topic_hash ,
501+ };
502+ out = tx_push (self , deadline , meta , make_topic_ep (subject_id ), payload , user_transfer_reference );
503+ }
504+ return out ;
479505}
480506
481507uint32_t udpard_tx_p2p (udpard_tx_t * const self ,
@@ -486,38 +512,62 @@ uint32_t udpard_tx_p2p(udpard_tx_t* const self,
486512 const udpard_prio_t priority ,
487513 const uint64_t transfer_id ,
488514 const udpard_bytes_t payload ,
515+ const bool ack_required ,
489516 void * const user_transfer_reference )
490517{
491- (void )self ;
492- (void )now ;
493- (void )deadline ;
494- (void )priority ;
495- (void )remote_uid ;
496- (void )remote_ep ;
497- (void )transfer_id ;
498- (void )payload ;
499- (void )user_transfer_reference ;
500- (void )tx_push ;
501- return 0 ;
518+ uint32_t out = 0 ;
519+ if ((self != NULL ) && (self -> local_uid != 0 ) && (remote_uid != 0 ) && (remote_ep .ip != 0 ) && (remote_ep .port != 0 ) &&
520+ (priority <= UDPARD_PRIORITY_MAX ) && ((payload .data != NULL ) || (payload .size == 0U ))) {
521+ self -> errors_expiration += tx_purge_expired (self , now );
522+ const meta_t meta = {
523+ .priority = priority ,
524+ .flag_ack = ack_required ,
525+ .transfer_payload_size = (uint32_t )payload .size ,
526+ .transfer_id = transfer_id ,
527+ .sender_uid = self -> local_uid ,
528+ .topic_hash = remote_uid ,
529+ };
530+ out = tx_push (self , deadline , meta , remote_ep , payload , user_transfer_reference );
531+ }
532+ return out ;
502533}
503534
504- udpard_tx_item_t * udpard_tx_peek (const udpard_tx_t * const self , const udpard_microsecond_t now )
535+ udpard_tx_item_t * udpard_tx_peek (udpard_tx_t * const self , const udpard_microsecond_t now )
505536{
506- (void )self ;
507- (void )now ;
508- return NULL ;
537+ udpard_tx_item_t * out = NULL ;
538+ if (self != NULL ) {
539+ self -> errors_expiration += tx_purge_expired (self , now );
540+ out = CAVL2_TO_OWNER (cavl2_min (self -> index_prio ), udpard_tx_item_t , index_prio );
541+ }
542+ return out ;
509543}
510544
511- void udpard_tx_pop (const udpard_tx_t * const self , udpard_tx_item_t * const item )
545+ void udpard_tx_pop (udpard_tx_t * const self , udpard_tx_item_t * const item )
512546{
513- (void )self ;
514- (void )item ;
547+ if ((self != NULL ) && (item != NULL )) {
548+ if (item -> next_in_transfer == NULL ) {
549+ cavl2_remove (& self -> index_prio , & item -> index_prio );
550+ cavl2_remove (& self -> index_deadline , & item -> index_deadline );
551+ } else { // constant-time update, super quick, just relink a few pointers!
552+ cavl2_replace (& self -> index_prio , & item -> index_prio , & item -> next_in_transfer -> index_prio );
553+ cavl2_replace (& self -> index_deadline , & item -> index_deadline , & item -> next_in_transfer -> index_deadline );
554+ }
555+ self -> queue_size -- ;
556+ }
515557}
516558
517559void udpard_tx_free (const udpard_tx_mem_resources_t memory , udpard_tx_item_t * const item )
518560{
519- (void )memory ;
520- (void )item ;
561+ if (item != NULL ) {
562+ UDPARD_ASSERT ((item -> index_prio .lr [0 ] == NULL ) && (item -> index_prio .up == NULL ) &&
563+ (item -> index_prio .lr [1 ] == NULL ));
564+ UDPARD_ASSERT ((item -> index_deadline .lr [0 ] == NULL ) && (item -> index_deadline .up == NULL ) &&
565+ (item -> index_deadline .lr [1 ] == NULL ));
566+ if (item -> datagram_payload .data != NULL ) {
567+ mem_free (memory .payload , item -> datagram_payload .size , item -> datagram_payload .data );
568+ }
569+ mem_free (memory .fragment , sizeof (udpard_tx_item_t ), item );
570+ }
521571}
522572
523573// --------------------------------------------- RX PIPELINE ---------------------------------------------
0 commit comments