LCOV - code coverage report
Current view: top level - disco/sleep - fd_sleep.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 73 81 90.1 %
Date: 2026-09-17 04:28:31 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_sleep.h"
       3             : #include "../topo/fd_topo.h"
       4             : 
       5             : #include <errno.h>
       6             : #include <float.h>
       7             : #include <time.h>
       8             : #include <linux/futex.h>
       9             : #include <sys/syscall.h>
      10             : #include <unistd.h>
      11             : 
      12          15 : FD_FN_CONST ulong fd_sleep_align    ( void ) { return FD_SLEEP_ALIGN;    }
      13           6 : FD_FN_CONST ulong fd_sleep_footprint( void ) { return sizeof(fd_sleep_t); }
      14             : 
      15             : void *
      16             : fd_sleep_new( void * shmem,
      17          12 :               double tick_per_ns ) {
      18          12 :   if( FD_UNLIKELY( !shmem ) ) {
      19           3 :     FD_LOG_WARNING(( "NULL shmem" ));
      20           3 :     return NULL;
      21           3 :   }
      22             : 
      23           9 :   if( FD_UNLIKELY( !(tick_per_ns>0.0 && tick_per_ns<=DBL_MAX) ) ) {
      24           3 :     FD_LOG_WARNING(( "bad tick_per_ns" ));
      25           3 :     return NULL;
      26           3 :   }
      27             : 
      28           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_sleep_align() ) ) ) {
      29           3 :     FD_LOG_WARNING(( "misaligned shmem" ));
      30           3 :     return NULL;
      31           3 :   }
      32             : 
      33           3 :   fd_sleep_t * sleep = (fd_sleep_t *)shmem;
      34           3 :   fd_memset( sleep, 0, fd_sleep_footprint() );
      35        1539 :   for( ulong i=0UL; i<FD_SLEEP_TILE_MAX; i++ ) sleep->tile[ i ].word = 1UL; /* running */
      36           3 :   sleep->tick_per_ns = tick_per_ns;
      37             : 
      38           3 :   FD_COMPILER_MFENCE();
      39           3 :   FD_VOLATILE( sleep->magic ) = FD_SLEEP_MAGIC;
      40           3 :   FD_COMPILER_MFENCE();
      41             : 
      42           3 :   return shmem;
      43           6 : }
      44             : 
      45             : ulong
      46             : fd_sleep_wake_table( fd_sleep_wake_t *      wake,
      47             :                      struct fd_topo const * topo,
      48          12 :                      ulong                  link_id ) {
      49          12 :   if( FD_UNLIKELY( topo->sleep_obj_id==ULONG_MAX ) ) return 0UL;
      50           9 :   ulong mask[ FD_SLEEP_BITS_CNT ] = {0};
      51         639 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
      52         630 :     fd_topo_tile_t const * consumer = &topo->tiles[ i ];
      53         666 :     for( ulong j=0UL; j<consumer->in_cnt; j++ ) {
      54          36 :       if( FD_UNLIKELY( consumer->in_link_id[ j ]==link_id && consumer->in_link_poll[ j ] ) ) {
      55           9 :         mask[ consumer->id>>6 ] |= 1UL<<(consumer->id&63UL);
      56           9 :       }
      57          36 :     }
      58         630 :   }
      59             : 
      60           9 :   ulong cnt = 0UL;
      61          81 :   for( ulong w=0UL; w<FD_SLEEP_BITS_CNT; w++ ) {
      62          72 :     if( FD_UNLIKELY( mask[ w ] ) ) wake[ cnt++ ] = (fd_sleep_wake_t){ .w=w, .mask=mask[ w ] };
      63          72 :   }
      64           9 :   return cnt;
      65          12 : }
      66             : 
      67             : fd_sleep_t *
      68           6 : fd_sleep_join( void * shsleep ) {
      69           6 :   if( FD_UNLIKELY( !shsleep ) ) {
      70           0 :     FD_LOG_WARNING(( "NULL shsleep" ));
      71           0 :     return NULL;
      72           0 :   }
      73             : 
      74           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shsleep, fd_sleep_align() ) ) ) {
      75           0 :     FD_LOG_WARNING(( "misaligned shsleep" ));
      76           0 :     return NULL;
      77           0 :   }
      78             : 
      79           6 :   fd_sleep_t * sleep = (fd_sleep_t *)shsleep;
      80             : 
      81           6 :   if( FD_UNLIKELY( sleep->magic!=FD_SLEEP_MAGIC ) ) {
      82           3 :     FD_LOG_WARNING(( "bad magic" ));
      83           3 :     return NULL;
      84           3 :   }
      85             : 
      86           3 :   return sleep;
      87           6 : }
      88             : 
      89             : int
      90             : fd_sleep_park_wait( fd_sleep_t const * sleep,
      91             :                     ulong *            word,
      92      300036 :                     long               deadline_ticks ) {
      93             :   /* Absolute timeout, anchored on a clock read taken before the tick
      94             :      read: preemption anywhere after can only shorten the sleep, never
      95             :      stretch it past deadline_ticks */
      96      300036 :   struct timespec ts;
      97      300036 :   clock_gettime( CLOCK_MONOTONIC, &ts );
      98      300036 :   long remaining = (long)((double)(deadline_ticks-fd_tickcount())/sleep->tick_per_ns);
      99      300036 :   if( FD_UNLIKELY( remaining<=0L ) ) return FD_SLEEP_UNPARK_DEADLINE;
     100      300033 :   long abs_ns = ts.tv_sec*(long)1e9 + ts.tv_nsec + remaining;
     101      300033 :   ts.tv_sec  = abs_ns/(long)1e9;
     102      300033 :   ts.tv_nsec = abs_ns%(long)1e9;
     103             : 
     104      300033 :   for(;;) {
     105      300033 :     long res = syscall( SYS_futex, (uint *)word, FUTEX_WAIT_BITSET, 0U, &ts, NULL, FUTEX_BITSET_MATCH_ANY );
     106      300033 :     if( FD_LIKELY( !res ) ) return FD_SLEEP_UNPARK_RING;
     107             : 
     108          33 :     switch( errno ) {
     109          30 :       case ETIMEDOUT: return FD_SLEEP_UNPARK_DEADLINE;
     110           3 :       case EAGAIN:    return FD_SLEEP_UNPARK_RING;  /* word already 1 */
     111           0 :       case EINTR:     continue;                     /* signal: same absolute timeout */
     112           0 :       default: FD_LOG_ERR(( "futex(FUTEX_WAIT_BITSET) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     113          33 :     }
     114          33 :   }
     115      300033 : }
     116             : 
     117             : void
     118      300000 : fd_sleep_wake_one( ulong * word ) {
     119      300000 :   FD_VOLATILE( word[0] ) = 1UL;
     120      300000 :   long res = syscall( SYS_futex, (uint *)word, FUTEX_WAKE, 1, NULL, NULL, 0 );
     121      300000 :   if( FD_UNLIKELY( -1L==res ) ) FD_LOG_ERR(( "futex(FUTEX_WAKE) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     122      300000 : }

Generated by: LCOV version 1.14