LCOV - code coverage report
Current view: top level - waltz/quic - fd_quic_svc_q.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 164 172 95.3 %
Date: 2025-10-13 04:42:14 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "fd_quic_svc_q.h"
       2             : #include "fd_quic_private.h"
       3             : #include "fd_quic_conn.h"
       4             : 
       5             : /* PRIVATE ************************************************/
       6             : 
       7             : #define PRQ_NAME fd_quic_svc_queue_prq
       8    14585036 : #define PRQ_T    fd_quic_svc_event_t
       9    14284529 : #define PRQ_TMP_ST(p,t) do { \
      10    14284529 :                          (p)[0] = (t); \
      11    14284529 :                          t.conn->svc_meta.private.prq_idx = (ulong)((p)-heap); \
      12    14284529 :                        } while( 0 )
      13    14584496 : #define PRQ_TIMEOUT_T long
      14             : #include "../../util/tmpl/fd_prq.c"
      15             : typedef fd_quic_svc_event_t fd_quic_svc_queue_prq_t;
      16             : 
      17             : 
      18             : /* SETUP FUNCTIONS *************************************************/
      19             : 
      20             : ulong
      21       11040 : fd_quic_svc_timers_footprint( ulong max_conn ) {
      22       11040 :   ulong l = FD_LAYOUT_INIT;
      23       11040 :   l = FD_LAYOUT_APPEND( l, alignof(fd_quic_svc_timers_t), sizeof(fd_quic_svc_timers_t) );
      24       11040 :   l = FD_LAYOUT_APPEND( l, fd_quic_svc_queue_prq_align(), fd_quic_svc_queue_prq_footprint( max_conn ) );
      25       11040 :   l = FD_LAYOUT_FINI(   l, fd_quic_svc_timers_align() );
      26       11040 :   return l;
      27       11040 : }
      28             : 
      29             : ulong
      30       36516 : fd_quic_svc_timers_align( void ) {
      31       36516 :   return fd_ulong_max( alignof( fd_quic_svc_timers_t ),
      32       36516 :                       fd_quic_svc_queue_prq_align() );
      33       36516 : }
      34             : 
      35             : fd_quic_svc_timers_t *
      36             : fd_quic_svc_timers_init( void            * mem,
      37             :                          ulong             max_conn,
      38        3396 :                          fd_quic_state_t * state ) {
      39        3396 :   if( FD_UNLIKELY( !mem ) ) {
      40           0 :     FD_LOG_ERR(( "fd_quic_svc_timers_init called with NULL mem" ));
      41           0 :     return NULL;
      42           0 :   }
      43             : 
      44        3396 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_quic_svc_timers_align() ) ) ) {
      45           0 :     FD_LOG_ERR(( "fd_quic_svc_timers_init called with misaligned mem" ));
      46           0 :     return NULL;
      47           0 :   }
      48             : 
      49        3396 :   FD_SCRATCH_ALLOC_INIT( l, mem );
      50        3396 :   fd_quic_svc_timers_t * timers  = FD_SCRATCH_ALLOC_APPEND( l,
      51        3396 :                                                             alignof(fd_quic_svc_timers_t),
      52        3396 :                                                             sizeof(fd_quic_svc_timers_t) );
      53        3396 :   uchar                * prq_mem = FD_SCRATCH_ALLOC_APPEND( l,
      54        3396 :                                                             fd_quic_svc_queue_prq_align(),
      55        3396 :                                                             fd_quic_svc_queue_prq_footprint( max_conn ) );
      56             : 
      57             : 
      58           0 :   timers->prq = fd_quic_svc_queue_prq_join( fd_quic_svc_queue_prq_new( prq_mem, max_conn ) );
      59        3396 :   if( FD_UNLIKELY( !timers->prq ) ) FD_LOG_ERR(( "fd_quic_svc_timers_init failed to join prq" ));
      60             : 
      61        3396 :   timers->instant.cnt  = 0U;
      62        3396 :   timers->instant.head = FD_QUIC_SVC_DLIST_IDX_INVAL;
      63        3396 :   timers->instant.tail = FD_QUIC_SVC_DLIST_IDX_INVAL;
      64             : 
      65        3396 :   timers->state = state;
      66             : 
      67        3396 :   return timers;
      68        3396 : }
      69             : 
      70             : void
      71    14427407 : fd_quic_svc_timers_init_conn( fd_quic_conn_t * conn ) {
      72    14427407 :   conn->svc_meta.next_timeout       = LONG_MAX;
      73    14427407 :   conn->svc_meta.private.prq_idx    = FD_QUIC_SVC_PRQ_IDX_INVAL;
      74    14427407 :   conn->svc_meta.private.svc_type   = FD_QUIC_SVC_CNT;
      75    14427407 : }
      76             : 
      77             : /* END SETUP FUNCTIONS *********************************************/
      78             : 
      79             : /* DLIST HELPER FUNCTIONS *******************************************/
      80             : 
      81             : static inline void
      82             : fd_quic_svc_dlist_insert_tail( fd_quic_svc_queue_t * queue,
      83             :                                fd_quic_state_t     * state,
      84    13779710 :                                fd_quic_conn_t      * conn ) {
      85             : 
      86    13779710 :   uint             conn_idx  = conn->conn_idx;
      87    13779710 :   fd_quic_conn_t * tail_conn = fd_quic_conn_at_idx( state, queue->tail );
      88             : 
      89    13779710 :   *fd_ptr_if( !!queue->cnt, &tail_conn->svc_meta.private.dlist.next , &queue->head) = conn_idx ;
      90    13779710 :   conn->svc_meta.private.dlist.prev = queue->tail;
      91    13779710 :   conn->svc_meta.private.dlist.next = FD_QUIC_SVC_DLIST_IDX_INVAL;
      92    13779710 :   queue->tail         = conn_idx;
      93    13779710 :   queue->cnt++;
      94    13779710 : }
      95             : 
      96             : static inline void
      97             : fd_quic_svc_dlist_remove( fd_quic_svc_queue_t * queue,
      98             :                           fd_quic_state_t     * state,
      99    13779695 :                           fd_quic_conn_t      * conn ) {
     100    13779695 :   uint conn_idx = conn->conn_idx;
     101    13779695 :   uint qhead    = queue->head;
     102    13779695 :   uint qtail    = queue->tail;
     103             : 
     104    13779695 :   fd_quic_conn_t * prev_conn = fd_quic_conn_at_idx( state, conn->svc_meta.private.dlist.prev );
     105    13779695 :   fd_quic_conn_t * next_conn = fd_quic_conn_at_idx( state, conn->svc_meta.private.dlist.next );
     106             : 
     107    13779695 :   *fd_ptr_if( conn_idx == qhead, &queue->head , &prev_conn->svc_meta.private.dlist.next) = conn->svc_meta.private.dlist.next;
     108    13779695 :   *fd_ptr_if( conn_idx == qtail, &queue->tail , &next_conn->svc_meta.private.dlist.prev) = conn->svc_meta.private.dlist.prev;
     109             : 
     110    13779695 :   conn->svc_meta.private.dlist.next = FD_QUIC_SVC_DLIST_IDX_INVAL;
     111    13779695 :   conn->svc_meta.private.dlist.prev = FD_QUIC_SVC_DLIST_IDX_INVAL;
     112    13779695 :   queue->cnt--;
     113    13779695 : }
     114             : 
     115             : /* TASK FUNCTIONS *************************************************/
     116             : 
     117             : void
     118             : fd_quic_svc_timers_cancel( fd_quic_svc_timers_t * timers,
     119       14337 :                            fd_quic_conn_t       * conn ) {
     120             : 
     121       14337 :   uint              svc_type = conn->svc_meta.private.svc_type;
     122       14337 :   fd_quic_state_t * state    = timers->state;
     123             : 
     124       14337 :   if( svc_type == FD_QUIC_SVC_INSTANT ) {
     125          39 :     fd_quic_svc_dlist_remove( &timers->instant, state, conn );
     126       14298 :   } else if( svc_type == FD_QUIC_SVC_DYNAMIC ) {
     127          84 :     fd_quic_svc_queue_prq_remove( timers->prq, conn->svc_meta.private.prq_idx );
     128          84 :   }
     129       14337 :   fd_quic_svc_timers_init_conn( conn );
     130       14337 : }
     131             : 
     132             : void
     133             : fd_quic_svc_timers_schedule( fd_quic_svc_timers_t * timers,
     134             :                              fd_quic_conn_t       * conn,
     135    55223243 :                              long                   now ) {
     136             : 
     137             :   /* if conn null or invalid, do not schedule */
     138    55223243 :   if( FD_UNLIKELY( !conn || conn->state == FD_QUIC_CONN_STATE_INVALID ) ) {
     139             :     /* cleaner/safer to check in here for now. If function call overhead
     140             :        becomes a constraint, move check to caller */
     141       13212 :     return;
     142       13212 :   }
     143             : 
     144    55210031 :   fd_quic_state_t * state        = timers->state;
     145    55210031 :   long              expiry       = conn->svc_meta.next_timeout;
     146    55210031 :   uint              old_svc_type = conn->svc_meta.private.svc_type;
     147    55210031 :   uint              new_svc_type = fd_uint_if( expiry == now, FD_QUIC_SVC_INSTANT, FD_QUIC_SVC_DYNAMIC );
     148    55210031 :   int               in_sched     = !(old_svc_type==FD_QUIC_SVC_CNT);
     149             : 
     150             :   /* no-op if already instant. Or if trying to reduce dynamic timer */
     151    55210031 :   int noop = !!(old_svc_type==FD_QUIC_SVC_INSTANT);
     152    55210031 :   if( in_sched && new_svc_type==FD_QUIC_SVC_DYNAMIC ) {
     153             :     /* in sched --> old_svc_type==FD_QUIC_SVC_DYNAMIC
     154             :        So just compare existing timer with current timer */
     155    27315472 :     ulong old_idx    = conn->svc_meta.private.prq_idx;
     156    27315472 :     long  old_expiry = timers->prq[old_idx].timeout;
     157    27315472 :     noop |= (old_expiry <= expiry);
     158    27315472 :   }
     159    55210031 :   if( noop ) return;
     160             : 
     161             :   /* cancel existing, must be dynamic */
     162    28063969 :   if( in_sched ) {
     163    13981925 :     fd_quic_svc_queue_prq_remove( timers->prq, conn->svc_meta.private.prq_idx );
     164    13981925 :   }
     165             : 
     166             :   /* Schedule in appropriate queue */
     167    28063969 :   conn->svc_meta.private.svc_type = new_svc_type;
     168             : 
     169    28063969 :   if( new_svc_type==FD_QUIC_SVC_INSTANT ) {
     170    13779710 :     fd_quic_svc_dlist_insert_tail( &timers->instant, state, conn );
     171    14284259 :   } else {
     172             :     /* FD_QUIC_SVC_DYNAMIC - use heap */
     173    14284259 :     fd_quic_svc_event_t e = {
     174    14284259 :       .conn    = conn,
     175    14284259 :       .timeout = expiry
     176    14284259 :     };
     177    14284259 :     fd_quic_svc_queue_prq_insert( timers->prq, &e );
     178    14284259 :   }
     179    28063969 : }
     180             : 
     181             : int
     182             : fd_quic_svc_timers_validate( fd_quic_svc_timers_t * timers,
     183          60 :                              fd_quic_t            * quic ) {
     184          60 :   fd_quic_state_t * state = fd_quic_get_state( quic );
     185             : 
     186             :   /* Validate DYNAMIC queue (heap) */
     187          60 :   ulong prq_cnt = fd_quic_svc_queue_prq_cnt( timers->prq );
     188      300111 :   for( ulong i=0; i<prq_cnt; i++ ) {
     189      300051 :     fd_quic_svc_event_t * event = timers->prq + i;
     190      300051 :     fd_quic_conn_t      * conn  = event->conn;
     191             : 
     192             :     /* conn and idx match for dynamic queue */
     193      300051 :     if( FD_UNLIKELY( conn->svc_meta.private.prq_idx != i ) ) return 0;
     194      300051 :     if( FD_UNLIKELY( conn->svc_meta.private.svc_type != FD_QUIC_SVC_DYNAMIC ) ) return 0;
     195             : 
     196             :     /* conn in prq at most once */
     197      300051 :     if( FD_UNLIKELY( conn->visited ) ) return 0;
     198      300051 :     conn->visited = 1U;
     199      300051 :   }
     200             : 
     201             :   /* Validate dlist */
     202          60 :   ulong instant_cnt = 0U;
     203          60 :   uint  curr        = timers->instant.head;
     204          63 :   while( curr != FD_QUIC_SVC_DLIST_IDX_INVAL ) {
     205           3 :     fd_quic_conn_t * conn = fd_quic_conn_at_idx( state, curr );
     206           3 :     if( FD_UNLIKELY( conn->svc_meta.private.svc_type != FD_QUIC_SVC_INSTANT ) ) return 0;
     207           3 :     if( FD_UNLIKELY( conn->visited ) ) return 0;
     208           3 :     conn->visited = 1U;
     209           3 :     curr = conn->svc_meta.private.dlist.next;
     210           3 :     instant_cnt++;
     211           3 :   }
     212          60 :   if( instant_cnt != timers->instant.cnt ) return 0;
     213             : 
     214             :   /* connections not in any queue should have INVALID idx */
     215          60 :   ulong const conn_cnt = quic->limits.conn_cnt;
     216      300558 :   for( ulong i=0; i<conn_cnt; i++ ) {
     217      300498 :     fd_quic_conn_t * conn = fd_quic_conn_at_idx( state, i );
     218      300498 :     if( !conn->visited && conn->svc_meta.private.prq_idx != FD_QUIC_SVC_PRQ_IDX_INVAL ) return 0;
     219      300498 :   }
     220             : 
     221          60 :   return 1;
     222          60 : }
     223             : 
     224             : fd_quic_svc_event_t
     225             : fd_quic_svc_timers_next( fd_quic_svc_timers_t * timers,
     226             :                          long                   now,
     227    90474520 :                          int                    pop ) {
     228    90474520 :   fd_quic_svc_event_t next = { .timeout = LONG_MAX, .conn = NULL };
     229             : 
     230             :   /* Priority: INSTANT > DYNAMIC */
     231             : 
     232             :   /* Check INSTANT queue first */
     233    90474520 :   if( FD_LIKELY( timers->instant.cnt ) ) {
     234    13827791 :     fd_quic_conn_t * conn = fd_quic_conn_at_idx( timers->state, timers->instant.head );
     235    13827791 :     next = (fd_quic_svc_event_t){.conn = conn, .timeout = fd_long_min( now, conn->svc_meta.next_timeout )};
     236             : 
     237    13827791 :     if( FD_LIKELY( pop ) ) {
     238    13779656 :       fd_quic_svc_dlist_remove( &timers->instant, timers->state, conn );
     239    13779656 :       fd_quic_svc_timers_init_conn( conn );
     240    13779656 :     }
     241             : 
     242    13827791 :     return next;
     243    13827791 :   }
     244             : 
     245             :   /* Check DYNAMIC queue (heap) */
     246    76646729 :   if( !fd_quic_svc_queue_prq_cnt( timers->prq ) ) return next;
     247    76641374 :   else if( pop && now < timers->prq[0].timeout ) return next;
     248      105498 :   else {
     249      105498 :     next = timers->prq[0];
     250      105498 :     if( FD_LIKELY( pop ) ) {
     251        2214 :       fd_quic_svc_queue_prq_remove_min( timers->prq );
     252        2214 :       fd_quic_svc_timers_init_conn( next.conn );
     253        2214 :     }
     254      105498 :     return next;
     255      105498 :   }
     256    76646729 : }
     257             : 
     258             : fd_quic_svc_event_t
     259             : fd_quic_svc_timers_get_event( fd_quic_svc_timers_t * timers,
     260             :                               fd_quic_conn_t       * conn,
     261        2091 :                               long                   now ) {
     262        2091 :   uint svc_type = conn->svc_meta.private.svc_type;
     263             : 
     264        2091 :   if( svc_type == FD_QUIC_SVC_INSTANT ) {
     265           0 :     return (fd_quic_svc_event_t){ .timeout = now, .conn = conn };
     266        2091 :   } else if (svc_type == FD_QUIC_SVC_DYNAMIC) {
     267        2088 :     ulong idx = conn->svc_meta.private.prq_idx;
     268        2088 :     return *(timers->prq + idx);
     269        2088 :   }
     270           3 :   return (fd_quic_svc_event_t){ .timeout = LONG_MAX, .conn = NULL };
     271        2091 : }
     272             : 
     273             : ulong
     274   104135025 : fd_quic_svc_timers_cnt_events( fd_quic_svc_timers_t * timers ) {
     275   104135025 :   return timers->instant.cnt +
     276   104135025 :          fd_quic_svc_queue_prq_cnt( timers->prq );
     277   104135025 : }

Generated by: LCOV version 1.14