LCOV - code coverage report
Current view: top level - discof/admin - fd_adminctl.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 239 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 23 0.0 %

          Line data    Source code
       1             : #include "fd_adminctl.h"
       2             : 
       3             : #include "../../util/log/fd_log.h"
       4             : 
       5             : #include <errno.h>
       6             : #include <signal.h>
       7             : #include <unistd.h>
       8             : 
       9           0 : #define FD_ADMINCTL_MAGIC          (0xF17EDA2C37AD0202UL)
      10           0 : #define FD_ADMINCTL_STATE_MASK     (7UL)
      11           0 : #define FD_ADMINCTL_SEQ_SHIFT      (3UL)
      12           0 : #define FD_ADMINCTL_SEQ_BITS       (8UL)
      13           0 : #define FD_ADMINCTL_SEQ_VALUE_MASK ((1UL<<FD_ADMINCTL_SEQ_BITS)-1UL)
      14           0 : #define FD_ADMINCTL_TS_SHIFT       (FD_ADMINCTL_SEQ_SHIFT+FD_ADMINCTL_SEQ_BITS)
      15           0 : #define FD_ADMINCTL_TS_BITS        (FD_ADMINCTL_PID_SHIFT-FD_ADMINCTL_TS_SHIFT)
      16           0 : #define FD_ADMINCTL_TS_VALUE_MASK  ((1UL<<FD_ADMINCTL_TS_BITS)-1UL)
      17           0 : #define FD_ADMINCTL_PID_SHIFT      (32UL)
      18             : #define FD_ADMINCTL_RESERVE_TTL    (5UL)
      19             : 
      20           0 : #define FD_ADMINCTL_STATE_FREE       (0UL)
      21           0 : #define FD_ADMINCTL_STATE_RESERVED   (1UL)
      22             : #define FD_ADMINCTL_STATE_PUBLISHED  (2UL)
      23           0 : #define FD_ADMINCTL_STATE_PROCESSING (3UL)
      24             : #define FD_ADMINCTL_STATE_DONE       (4UL)
      25             : 
      26             : struct fd_adminctl_slot {
      27             :   ulong state_pid_seq;
      28             :   ulong cmd;
      29             :   ulong result;
      30             :   ulong payload_sz;
      31             :   uchar payload[ FD_ADMINCTL_PAYLOAD_MAX ];
      32             :   ulong step_cnt; /* step lines added to the command, the newest FD_ADMINCTL_STEP_CNT are in step */
      33             :   char  step[ FD_ADMINCTL_STEP_CNT ][ FD_ADMINCTL_STEP_MAX ];
      34             : };
      35             : typedef struct fd_adminctl_slot fd_adminctl_slot_t;
      36             : 
      37             : struct fd_adminctl_private {
      38             :   ulong               magic; /* ==FD_ADMINCTL_MAGIC */
      39             :   ulong               next_request_id;
      40             :   ulong               poll_idx;
      41             :   fd_adminctl_slot_t  slots[ FD_ADMINCTL_SLOT_CNT ];
      42             : };
      43             : typedef struct fd_adminctl_private fd_adminctl_t;
      44             : 
      45             : static inline ulong
      46             : fd_adminctl_state_pid_seq( uint  pid,
      47             :                            ulong seq,
      48             :                            ulong reserve_ts_sec,
      49           0 :                            ulong state ) {
      50           0 :   return (((ulong)pid)<<FD_ADMINCTL_PID_SHIFT) |
      51           0 :          ((reserve_ts_sec & FD_ADMINCTL_TS_VALUE_MASK)<<FD_ADMINCTL_TS_SHIFT) |
      52           0 :          ((seq & FD_ADMINCTL_SEQ_VALUE_MASK)<<FD_ADMINCTL_SEQ_SHIFT) |
      53           0 :          state;
      54           0 : }
      55             : 
      56             : static inline ulong
      57           0 : fd_adminctl_state( ulong state_pid_seq ) {
      58           0 :   return state_pid_seq & FD_ADMINCTL_STATE_MASK;
      59           0 : }
      60             : 
      61             : static inline ulong
      62             : fd_adminctl_state_update( ulong state_pid_seq,
      63           0 :                                   ulong state ) {
      64           0 :   return (state_pid_seq & ~FD_ADMINCTL_STATE_MASK) | state;
      65           0 : }
      66             : 
      67             : static inline ulong
      68           0 : fd_adminctl_reserve_ts_sec( ulong state_pid_seq ) {
      69           0 :   return (state_pid_seq>>FD_ADMINCTL_TS_SHIFT) & FD_ADMINCTL_TS_VALUE_MASK;
      70           0 : }
      71             : 
      72             : static inline uint
      73           0 : fd_adminctl_pid( ulong state_pid_seq ) {
      74           0 :   return (uint)(state_pid_seq>>FD_ADMINCTL_PID_SHIFT);
      75           0 : }
      76             : 
      77             : static inline ulong
      78           0 : fd_adminctl_now_sec( void ) {
      79           0 :   return (ulong)(fd_log_wallclock() / 1000000000L);
      80           0 : }
      81             : 
      82             : static inline ulong
      83             : fd_adminctl_elapsed_sec( ulong now_sec,
      84           0 :                          ulong then_sec ) {
      85           0 :   return (now_sec - then_sec) & FD_ADMINCTL_TS_VALUE_MASK;
      86           0 : }
      87             : 
      88             : static int
      89           0 : fd_adminctl_pid_alive( uint pid ) {
      90           0 :   if( FD_UNLIKELY( !pid ) ) return 0;
      91           0 :   if( FD_UNLIKELY( kill( (pid_t)pid, 0 ) ) ) {
      92           0 :     if( FD_LIKELY( errno==ESRCH ) ) return 0;
      93           0 :     return 1;
      94           0 :   }
      95           0 :   return 1;
      96           0 : }
      97             : 
      98             : static fd_adminctl_slot_t *
      99             : fd_adminctl_slot_laddr( fd_adminctl_t * adminctl,
     100           0 :                         ulong           slot_id ) {
     101           0 :   return &adminctl->slots[ slot_id ];
     102           0 : }
     103             : 
     104             : FD_FN_CONST ulong
     105           0 : fd_adminctl_align( void ) {
     106           0 :   return FD_ADMINCTL_ALIGN;
     107           0 : }
     108             : 
     109             : FD_FN_CONST ulong
     110           0 : fd_adminctl_footprint( void ) {
     111           0 :   return sizeof(fd_adminctl_t);
     112           0 : }
     113             : 
     114             : void *
     115           0 : fd_adminctl_new( void * shmem ) {
     116           0 :   fd_adminctl_t * adminctl = (fd_adminctl_t *)shmem;
     117             : 
     118           0 :   if( FD_UNLIKELY( !shmem ) ) {
     119           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     120           0 :     return NULL;
     121           0 :   }
     122             : 
     123           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_adminctl_align() ) ) ) {
     124           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     125           0 :     return NULL;
     126           0 :   }
     127             : 
     128           0 :   fd_memset( adminctl, 0, fd_adminctl_footprint() );
     129             : 
     130           0 :   FD_COMPILER_MFENCE();
     131           0 :   FD_VOLATILE( adminctl->magic ) = FD_ADMINCTL_MAGIC;
     132             : 
     133           0 :   return (void *)adminctl;
     134           0 : }
     135             : 
     136             : fd_adminctl_t *
     137           0 : fd_adminctl_join( void * shadminctl ) {
     138             : 
     139           0 :   if( FD_UNLIKELY( !shadminctl ) ) {
     140           0 :     FD_LOG_WARNING(( "NULL shadminctl" ));
     141           0 :     return NULL;
     142           0 :   }
     143             : 
     144           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shadminctl, fd_adminctl_align() ) ) ) {
     145           0 :     FD_LOG_WARNING(( "misaligned shadminctl" ));
     146           0 :     return NULL;
     147           0 :   }
     148             : 
     149           0 :   fd_adminctl_t * adminctl = (fd_adminctl_t *)shadminctl;
     150             : 
     151           0 :   if( FD_UNLIKELY( adminctl->magic!=FD_ADMINCTL_MAGIC ) ) {
     152           0 :     FD_LOG_WARNING(( "bad magic" ));
     153           0 :     return NULL;
     154           0 :   }
     155             : 
     156           0 :   return adminctl;
     157           0 : }
     158             : 
     159             : ulong
     160             : fd_adminctl_reserve( fd_adminctl_t * adminctl,
     161             :                      void **         payload_out,
     162           0 :                      ulong *         payload_max_out ) {
     163             : 
     164             :   /* Identify the command process with a pid and a monotonically
     165             :      increasing sequence number. */
     166           0 :   uint  pid = (uint)getpid();
     167           0 :   ulong seq = FD_ATOMIC_ADD_AND_FETCH( &adminctl->next_request_id, 1UL );
     168             : 
     169             :   /* Track the pid of a process which may be hung */
     170           0 :   uint  hung_pid = UINT_MAX;
     171           0 :   ulong now_sec  = fd_adminctl_now_sec();
     172             : 
     173           0 :   for( ulong slot_id=0UL; slot_id<FD_ADMINCTL_SLOT_CNT; slot_id++ ) {
     174           0 :     fd_adminctl_slot_t * slot          = fd_adminctl_slot_laddr( adminctl, slot_id );
     175           0 :     ulong                state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     176           0 :     uint                 owner_pid     = fd_adminctl_pid( state_pid_seq );
     177             : 
     178             :     /* Reclaim a slot if it's a dead command.  The conditions for
     179             :        reclaiming a slot are:
     180             :        - the slot is in a command owned state (RESERVED or DONE)
     181             :        - the process for the slot is dead */
     182           0 :     ulong state = fd_adminctl_state( state_pid_seq );
     183           0 :     if( FD_UNLIKELY( (state==FD_ADMINCTL_STATE_RESERVED || state==FD_ADMINCTL_STATE_DONE) && !fd_adminctl_pid_alive( owner_pid ) ) ) {
     184           0 :       FD_LOG_WARNING(( "a dead command process (pid=%u) has been detected.  This is likely the "
     185           0 :                        "result of a process being killed before it issued the command "
     186           0 :                        "or consumed the result of the command", owner_pid ));
     187           0 :       ulong free_state_pid_seq = fd_adminctl_state_update( state_pid_seq, FD_ADMINCTL_STATE_FREE );
     188           0 :       if( FD_LIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq, state_pid_seq, free_state_pid_seq )==state_pid_seq ) ) {
     189           0 :         state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     190           0 :         state         = fd_adminctl_state( state_pid_seq );
     191           0 :       } else {
     192           0 :         continue;
     193           0 :       }
     194           0 :     }
     195             : 
     196             :     /* If a slot is reserved and seems to be hung, track the pid to
     197             :        notify the caller.  Note that kill(pid,0) only checks the pid
     198             :        number; a reused pid can make a dead owner look hung. */
     199           0 :     if( FD_UNLIKELY( state==FD_ADMINCTL_STATE_RESERVED ) ) {
     200           0 :       ulong reserve_ts_sec = fd_adminctl_reserve_ts_sec( state_pid_seq );
     201           0 :       if( FD_UNLIKELY( fd_adminctl_pid_alive( owner_pid ) ) ) {
     202           0 :         if( FD_UNLIKELY( fd_adminctl_elapsed_sec( now_sec, reserve_ts_sec )>FD_ADMINCTL_RESERVE_TTL ) ) {
     203           0 :           hung_pid = owner_pid;
     204           0 :         }
     205           0 :       }
     206           0 :     }
     207             : 
     208           0 :     if( FD_UNLIKELY( state!=FD_ADMINCTL_STATE_FREE ) ) continue;
     209             : 
     210           0 :     ulong reserved_state_pid_seq = fd_adminctl_state_pid_seq( pid, seq, now_sec, FD_ADMINCTL_STATE_RESERVED );
     211           0 :     if( FD_UNLIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq, state_pid_seq, reserved_state_pid_seq )!=state_pid_seq ) ) continue;
     212             : 
     213           0 :     fd_memzero_explicit( slot->payload, sizeof(slot->payload) );
     214           0 :     *payload_out     = slot->payload;
     215           0 :     *payload_max_out = FD_ADMINCTL_PAYLOAD_MAX;
     216           0 :     return slot_id;
     217           0 :   }
     218             : 
     219           0 :   if( FD_UNLIKELY( hung_pid!=UINT_MAX ) ) {
     220           0 :     FD_LOG_WARNING(( "Unable to run command as there is another process (pid=%u) attempting to run a "
     221           0 :                      "command which appears to be hung (or the pid may have been reused) and has not "
     222           0 :                      "executed for over 5 seconds. Consider forcefully killing the process and "
     223           0 :                      "retrying the command.", hung_pid ));
     224             : 
     225           0 :   }
     226             : 
     227           0 :   return ULONG_MAX;
     228           0 : }
     229             : 
     230             : void
     231             : fd_adminctl_publish( fd_adminctl_t * adminctl,
     232             :                      ulong           slot_id,
     233             :                      ulong           cmd_id,
     234           0 :                      ulong           payload_sz ) {
     235             : 
     236             :   /* Now that the caller has written the payload into the adminctl's
     237             :      app region, we can publish the command to the admin tile.  At this
     238             :      point, the admin tile will own the command and return a result. */
     239           0 :   if( FD_UNLIKELY( slot_id>=FD_ADMINCTL_SLOT_CNT ) ) FD_LOG_CRIT(( "bad slot_id %lu", slot_id ));
     240             : 
     241           0 :   fd_adminctl_slot_t * slot          = fd_adminctl_slot_laddr( adminctl, slot_id );
     242           0 :   ulong                state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     243           0 :   if( FD_UNLIKELY( fd_adminctl_state( state_pid_seq )!=FD_ADMINCTL_STATE_RESERVED ) ) FD_LOG_CRIT(( "adminctl publish without reservation" ));
     244             : 
     245           0 :   slot->cmd        = cmd_id;
     246           0 :   slot->payload_sz = payload_sz;
     247           0 :   slot->step_cnt   = 0UL;
     248             : 
     249           0 :   if( FD_UNLIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq,
     250           0 :                                   state_pid_seq,
     251           0 :                                   fd_adminctl_state_update( state_pid_seq, FD_ADMINCTL_STATE_PUBLISHED ) )!=state_pid_seq ) ) {
     252           0 :     FD_LOG_ERR(( "The command process is in an unexpected and invalid state while sending the "
     253           0 :                  "the command to the running firedancer.  This is likely the result of a bug. "
     254           0 :                  "Please report this to the firedancer team." ));
     255           0 :   }
     256           0 : }
     257             : 
     258             : ulong
     259             : fd_adminctl_poll( fd_adminctl_t * adminctl,
     260             :                   ulong *         slot_id_out,
     261             :                   void **         payload_out,
     262           0 :                   ulong *         payload_sz_out ) {
     263             : 
     264           0 :   ulong                slot_id = adminctl->poll_idx++ % FD_ADMINCTL_SLOT_CNT;
     265           0 :   fd_adminctl_slot_t * slot    = fd_adminctl_slot_laddr( adminctl, slot_id );
     266             : 
     267           0 :   ulong state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     268           0 :   FD_COMPILER_MFENCE();
     269             : 
     270           0 :   if( FD_UNLIKELY( fd_adminctl_state( state_pid_seq )!=FD_ADMINCTL_STATE_PUBLISHED ) ) return FD_ADMINCTL_CMD_IDLE;
     271             : 
     272           0 :   ulong cmd_id     = slot->cmd;
     273           0 :   ulong payload_sz = slot->payload_sz;
     274             : 
     275           0 :   ulong processing_state_pid_seq = fd_adminctl_state_update( state_pid_seq, FD_ADMINCTL_STATE_PROCESSING );
     276           0 :   if( FD_UNLIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq, state_pid_seq, processing_state_pid_seq )!=state_pid_seq ) ) return FD_ADMINCTL_CMD_IDLE;
     277             : 
     278           0 :   *slot_id_out    = slot_id;
     279           0 :   *payload_out    = slot->payload;
     280           0 :   *payload_sz_out = payload_sz;
     281           0 :   return cmd_id;
     282           0 : }
     283             : 
     284             : void
     285             : fd_adminctl_complete_response( fd_adminctl_t * adminctl,
     286             :                                ulong           slot_id,
     287             :                                ulong           result,
     288             :                                void const *    resp,
     289           0 :                                ulong           resp_sz ) {
     290             : 
     291           0 :   if( FD_UNLIKELY( resp_sz>FD_ADMINCTL_PAYLOAD_MAX ) ) FD_LOG_CRIT(( "bad resp_sz %lu", resp_sz ));
     292             : 
     293           0 :   fd_adminctl_slot_t * slot          = fd_adminctl_slot_laddr( adminctl, slot_id );
     294           0 :   ulong                state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     295             : 
     296           0 :   if( FD_UNLIKELY( fd_adminctl_state( state_pid_seq )!=FD_ADMINCTL_STATE_PROCESSING ) ) FD_LOG_ERR(( "adminctl complete without processing command" ));
     297             : 
     298           0 :   fd_memzero_explicit( slot->payload, slot->payload_sz );
     299           0 :   if( FD_UNLIKELY( resp_sz ) ) memcpy( slot->payload, resp, resp_sz );
     300           0 :   slot->payload_sz = resp_sz;
     301           0 :   slot->result     = result;
     302           0 :   if( FD_UNLIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq,
     303           0 :                                   state_pid_seq,
     304           0 :                                   fd_adminctl_state_update( state_pid_seq, FD_ADMINCTL_STATE_DONE ) )!=state_pid_seq ) )
     305           0 :     FD_LOG_ERR(( "invariant violation: adminctl_complete state update failed" ));
     306           0 : }
     307             : 
     308             : void
     309             : fd_adminctl_complete( fd_adminctl_t * adminctl,
     310             :                       ulong           slot_id,
     311           0 :                       ulong           result ) {
     312           0 :   fd_adminctl_complete_response( adminctl, slot_id, result, NULL, 0UL );
     313           0 : }
     314             : 
     315             : void
     316             : fd_adminctl_step( fd_adminctl_t * adminctl,
     317             :                   ulong           slot_id,
     318           0 :                   char const *    step ) {
     319           0 :   fd_adminctl_slot_t * slot = fd_adminctl_slot_laddr( adminctl, slot_id );
     320           0 :   if( FD_UNLIKELY( fd_adminctl_state( __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE ) )!=FD_ADMINCTL_STATE_PROCESSING ) ) {
     321           0 :     FD_LOG_ERR(( "adminctl step without processing command" ));
     322           0 :   }
     323           0 :   ulong cnt = slot->step_cnt;
     324           0 :   fd_cstr_ncpy( slot->step[ cnt%FD_ADMINCTL_STEP_CNT ], step, FD_ADMINCTL_STEP_MAX );
     325           0 :   FD_COMPILER_MFENCE();
     326           0 :   FD_VOLATILE( slot->step_cnt ) = cnt+1UL;
     327           0 : }
     328             : 
     329             : static void
     330             : fd_adminctl_show_steps( fd_adminctl_slot_t const * slot,
     331             :                         ulong *                    shown,
     332           0 :                         fd_adminctl_step_fn_t      step_fn ) {
     333           0 :   ulong cnt = FD_VOLATILE_CONST( slot->step_cnt );
     334           0 :   FD_COMPILER_MFENCE();
     335           0 :   if( FD_UNLIKELY( cnt-*shown>FD_ADMINCTL_STEP_CNT-1UL ) ) *shown = cnt-(FD_ADMINCTL_STEP_CNT-1UL);
     336           0 :   for( ; *shown<cnt; (*shown)++ ) {
     337           0 :     char line[ FD_ADMINCTL_STEP_MAX ];
     338           0 :     fd_memcpy( line, slot->step[ *shown%FD_ADMINCTL_STEP_CNT ], FD_ADMINCTL_STEP_MAX );
     339           0 :     line[ FD_ADMINCTL_STEP_MAX-1UL ] = '\0';
     340           0 :     FD_COMPILER_MFENCE();
     341           0 :     if( FD_UNLIKELY( FD_VOLATILE_CONST( slot->step_cnt )-*shown>FD_ADMINCTL_STEP_CNT-1UL ) ) continue; /* overwritten while copied */
     342           0 :     step_fn( line );
     343           0 :   }
     344           0 : }
     345             : 
     346             : ulong
     347             : fd_adminctl_wait_response( fd_adminctl_t * adminctl,
     348             :                            ulong           slot_id,
     349             :                            void *          resp,
     350             :                            ulong           resp_max,
     351           0 :                            ulong *         resp_sz_out ) {
     352           0 :   return fd_adminctl_wait_steps( adminctl, slot_id, resp, resp_max, resp_sz_out, NULL );
     353           0 : }
     354             : 
     355             : ulong
     356             : fd_adminctl_wait_steps( fd_adminctl_t *       adminctl,
     357             :                         ulong                 slot_id,
     358             :                         void *                resp,
     359             :                         ulong                 resp_max,
     360             :                         ulong *               resp_sz_out,
     361           0 :                         fd_adminctl_step_fn_t step_fn ) {
     362             : 
     363           0 :   fd_adminctl_slot_t * slot = fd_adminctl_slot_laddr( adminctl, slot_id );
     364             : 
     365           0 :   uint  pid   = (uint)getpid();
     366           0 :   ulong shown = 0UL;
     367             : 
     368           0 :   for(;;) {
     369           0 :     ulong state_pid_seq = __atomic_load_n( &slot->state_pid_seq, __ATOMIC_ACQUIRE );
     370           0 :     FD_COMPILER_MFENCE();
     371             : 
     372           0 :     ulong state = fd_adminctl_state( state_pid_seq );
     373           0 :     if( FD_UNLIKELY( fd_adminctl_pid( state_pid_seq )!=pid ||
     374           0 :                      (state!=FD_ADMINCTL_STATE_PUBLISHED &&
     375           0 :                       state!=FD_ADMINCTL_STATE_PROCESSING &&
     376           0 :                       state!=FD_ADMINCTL_STATE_DONE) ) ) {
     377           0 :       FD_LOG_ERR(( "The command process is in an unexpected and invalid state while waiting for "
     378           0 :                    "the command to complete.  This is likely the result of a bug in firedancer. "
     379           0 :                    "Please report this to the firedancer team." ));
     380           0 :     }
     381             : 
     382           0 :     if( FD_UNLIKELY( step_fn ) ) fd_adminctl_show_steps( slot, &shown, step_fn );
     383             : 
     384           0 :     if( FD_LIKELY( state==FD_ADMINCTL_STATE_DONE ) ) {
     385           0 :       ulong result  = slot->result;
     386           0 :       ulong resp_sz = fd_ulong_min( slot->payload_sz, FD_ADMINCTL_PAYLOAD_MAX );
     387           0 :       if( FD_UNLIKELY( resp ) ) memcpy( resp, slot->payload, fd_ulong_min( resp_sz, resp_max ) );
     388           0 :       if( FD_UNLIKELY( resp_sz_out ) ) *resp_sz_out = resp_sz;
     389           0 :       fd_memzero_explicit( slot->payload, resp_sz );
     390           0 :       if( FD_LIKELY( FD_ATOMIC_CAS( &slot->state_pid_seq,
     391           0 :                                     state_pid_seq,
     392           0 :                                     fd_adminctl_state_update( state_pid_seq, FD_ADMINCTL_STATE_FREE ) )==state_pid_seq ) ) {
     393           0 :         return result;
     394           0 :       }
     395           0 :     }
     396           0 :     FD_SPIN_PAUSE();
     397           0 :   }
     398           0 : }
     399             : 
     400             : ulong
     401             : fd_adminctl_wait( fd_adminctl_t * adminctl,
     402           0 :                   ulong           slot_id ) {
     403           0 :   return fd_adminctl_wait_response( adminctl, slot_id, NULL, 0UL, NULL );
     404           0 : }

Generated by: LCOV version 1.14