LCOV - code coverage report
Current view: top level - discof/capture - fd_solcap_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 206 0.0 %
Date: 2025-12-28 05:17:03 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #include "../../disco/topo/fd_topo.h"
       2             : #include "../../util/log/fd_log.h"
       3             : #include "../../tango/dcache/fd_dcache.h"
       4             : #include "../../tango/fd_tango_base.h"
       5             : 
       6             : #include <errno.h>
       7             : #include <fcntl.h>
       8             : #include <stdio.h>
       9             : #include <unistd.h>
      10             : #include <sys/stat.h>
      11             : 
      12             : #include "../../flamenco/capture/fd_capture_ctx.h"
      13             : #include "../../flamenco/capture/fd_solcap_writer.h"
      14             : #include "generated/fd_solcap_tile_seccomp.h"
      15             : 
      16             : 
      17             : /* The solcap tile is responsible for managing capture context
      18             :    for debugging runtime execution.
      19             : 
      20             :    The tile is enabled when capture context is enabled in the config.
      21             : 
      22             :    ```
      23             :    [capture]
      24             :     solcap_capture = "/path/to/filename.solcap.pcapng"
      25             :    ```
      26             : 
      27             :    When enabled, each tile that writes to solcap will initalize
      28             :    a mcache/dcache pair to use as a shared buffer to communicate with
      29             :    the solcap tile. Each tile that requires solcap writes will declare
      30             :    their own capture context to pass into runtime execution or post
      31             :    execution to write to the buffer via API's provided in the capture
      32             :    context and notify the solcap tile. The solcap tile will then
      33             :    process the messages from the link and write out to the file.
      34             : 
      35             :    More information about capture context in fd_capture_ctx.h
      36             : 
      37             :    Solcap Tile:
      38             : 
      39             :    The solcap tile is initialized with the incoming links from the
      40             :    topology, for each tile that requires solcap writes. The handling for
      41             :    messages is slightly altered from that of the normal stem run loop.
      42             : 
      43             :    The messages sent to the solcap tile are bounded by the size of the
      44             :    10mb (size of account data) + (much smaller) header information. In
      45             :    order to handle the larger messages in an efficient manner,
      46             :    the tile providing the data will send the data in chunks of at most
      47             :    128kb, on a link ~4mb. This is in order to avoid cache trashing. This
      48             :    is done by using a custom input selection control to shuffle the
      49             :    incoming frags and origin in-link only if the current message has
      50             :    been read completely using the SOM/EOM flags.
      51             : 
      52             :    The recent-only mode is a mode that allows for the capture of the
      53             :    last N slots of the execution. This is useful for debugging runtime
      54             :    on a live network. The mode is enabled by setting the recent_only
      55             :    configuration to 1. The number of slots per file is set by the
      56             :    recent_slots_per_file configuration. The default is 128 slots per
      57             :    file. The files are named recent_0.solcap, recent_1.solcap,. The
      58             :    files are rotated when the current file reaches the number of slots
      59             :    per file.
      60             : */
      61             : 
      62             : struct fd_solcap_tile_ctx {
      63             :   ulong tile_idx;
      64             : 
      65             :   ulong    msg_idx;
      66             :   ushort   msg_set_sig;
      67             :   ulong    msg_set_slot;
      68             :   uint     block_len;
      69             : 
      70             :   /* Capture context management */
      71             :   fd_capture_ctx_t  * capture_ctx;
      72             :   fd_capture_link_t * capctx_type;
      73             : 
      74             :   int fd;                             /* Current file descriptor */
      75             : 
      76             :   /* Recent-only rotating capture state */
      77             :   int   recent_only;                  /* 1 if using 2-file flip-flop, 0 for single file */
      78             :   int   recent_fds[2];                /* File descriptors for flip-flop and system calls */
      79             :   ulong recent_current_idx;           /* Current file index (0 or 1) */
      80             :   ulong recent_file_start_slot;       /* Slot number when current file was started (ULONG_MAX = uninitialized) */
      81             :   ulong recent_slots_per_file;        /* Number of slots per file */
      82             : 
      83             :   /* Incoming links for mcache/dcache processing */
      84             :   struct {
      85             :     fd_wksp_t * mem;
      86             :     ulong       chunk0;
      87             :     ulong       wmark;
      88             :     ulong       mtu;
      89             :   } in[32];
      90             : 
      91             :   ulong in_cnt;
      92             : 
      93             :   /* Track which input link we're currently processing */
      94             :   ulong current_in_idx;  /* ULONG_MAX means no active message */
      95             : 
      96             : };
      97             : 
      98             : typedef struct fd_solcap_tile_ctx fd_solcap_tile_ctx_t;
      99             : 
     100             : FD_FN_CONST static inline ulong
     101           0 : scratch_align( void ) {
     102           0 :   return 128UL;
     103           0 : }
     104             : 
     105             : FD_FN_PURE static inline ulong
     106           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
     107           0 :   (void)tile;
     108           0 :   ulong l = FD_LAYOUT_INIT;
     109           0 :   l = FD_LAYOUT_APPEND ( l, alignof(fd_solcap_tile_ctx_t), sizeof(fd_solcap_tile_ctx_t) );
     110           0 :   l = FD_LAYOUT_APPEND ( l, fd_capture_ctx_align(),         fd_capture_ctx_footprint() );
     111           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
     112           0 : }
     113             : 
     114             : static ulong
     115             : populate_allowed_seccomp( fd_topo_t const *      topo,
     116             :                           fd_topo_tile_t const * tile,
     117             :                           ulong                  out_cnt,
     118           0 :                           struct sock_filter *   out ) {
     119           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     120           0 :   fd_solcap_tile_ctx_t const * ctx = (fd_solcap_tile_ctx_t const *)scratch;
     121             : 
     122           0 :   uint solcap_fd_0 = ctx->recent_only ? (uint)ctx->recent_fds[0] : (uint)ctx->fd;
     123           0 :   uint solcap_fd_1 = ctx->recent_only ? (uint)ctx->recent_fds[1] : (uint)ctx->fd;
     124             : 
     125           0 :   populate_sock_filter_policy_fd_solcap_tile( out_cnt,
     126           0 :                                               out,
     127           0 :                                               (uint)fd_log_private_logfile_fd(),
     128           0 :                                               solcap_fd_0,
     129           0 :                                               solcap_fd_1 );
     130           0 :   return sock_filter_policy_fd_solcap_tile_instr_cnt;
     131           0 : }
     132             : 
     133             : static ulong
     134             : populate_allowed_fds( fd_topo_t const *      topo,
     135             :                       fd_topo_tile_t const * tile,
     136             :                       ulong                  out_fds_cnt FD_PARAM_UNUSED,
     137           0 :                       int *                  out_fds ) {
     138           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     139           0 :   fd_solcap_tile_ctx_t const * ctx = (fd_solcap_tile_ctx_t const *)scratch;
     140             : 
     141           0 :   ulong out_cnt = 0UL;
     142             : 
     143           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     144           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     145           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd();
     146             : 
     147           0 :   if( ctx->recent_only ) {
     148             :     /* In recent_only mode, allow both flip-flop file descriptors */
     149           0 :     if( FD_LIKELY( -1!=ctx->recent_fds[0] ) )
     150           0 :       out_fds[ out_cnt++ ] = ctx->recent_fds[0];
     151           0 :     if( FD_LIKELY( -1!=ctx->recent_fds[1] ) )
     152           0 :       out_fds[ out_cnt++ ] = ctx->recent_fds[1];
     153           0 :   } else {
     154             :     /* Traditional single file mode */
     155           0 :     if( FD_LIKELY( -1!=ctx->fd ) )
     156           0 :       out_fds[ out_cnt++ ] = ctx->fd;
     157           0 :   }
     158             : 
     159           0 :   return out_cnt;
     160           0 : }
     161             : 
     162             : /* fd_capctx_buf_process_msg processes a message fragment from the
     163             :    shared buffer and writes it to the solcap file using the solcap
     164             :    writer API.
     165             : 
     166             :    Returns block_len, the total PCAPNG Enhanced Packet Block (EPB)
     167             :    length in bytes. This value represents the complete size of the
     168             :    PCAPNG block including:
     169             :    - EPB header (28 bytes)
     170             :    - Internal chunk header
     171             :    - Message payload data
     172             :    - Padding (to align to 4-byte boundary)
     173             :    - Block footer (4 bytes)
     174             : 
     175             :    For messages that span multiple fragments:
     176             :    - Only the first fragment (SOM) returns a non-zero block_len,
     177             :      representing the total calculated block size
     178             :    - Continuation fragments return 0 as they don't write EPB headers
     179             :    - The block_len from SOM is saved and used when writing the EPB
     180             :      footer on the final fragment (EOM) */
     181             : /* fd_capctx_buf_process_som processes the first fragment (SOM) of a
     182             :    message and writes the appropriate header structures.
     183             : 
     184             :    Returns block_len, the total PCAPNG Enhanced Packet Block (EPB)
     185             :    length in bytes for this message. */
     186             : uint
     187             : fd_capctx_buf_process_som( fd_solcap_tile_ctx_t * ctx,
     188             :                            fd_solcap_buf_msg_t *  msg_hdr,
     189           0 :                            char *                 actual_data ) {
     190           0 :   uint block_len = 0U;
     191           0 :   FD_TEST( ctx->capture_ctx->capture != NULL );
     192             : 
     193           0 :   switch( msg_hdr->sig ) {
     194           0 :   case SOLCAP_WRITE_ACCOUNT: {
     195           0 :     fd_solcap_account_update_hdr_t * account_update = fd_type_pun( actual_data );
     196           0 :     block_len = fd_solcap_write_account_hdr( ctx->capture_ctx->capture, msg_hdr, account_update );
     197           0 :     break;
     198           0 :   }
     199           0 :   case SOLCAP_WRITE_BANK_PREIMAGE: {
     200           0 :     fd_solcap_bank_preimage_t * bank_preimage = fd_type_pun( actual_data );
     201           0 :     block_len = fd_solcap_write_bank_preimage( ctx->capture_ctx->capture, msg_hdr, bank_preimage );
     202           0 :     break;
     203           0 :   }
     204           0 :   case SOLCAP_STAKE_REWARDS_BEGIN: {
     205           0 :     fd_solcap_stake_rewards_begin_t * stake_rewards_begin = fd_type_pun( actual_data );
     206           0 :     block_len = fd_solcap_write_stake_rewards_begin( ctx->capture_ctx->capture, msg_hdr, stake_rewards_begin );
     207           0 :     break;
     208           0 :   }
     209           0 :   case SOLCAP_STAKE_REWARD_EVENT: {
     210           0 :     fd_solcap_stake_reward_event_t * stake_reward_event = fd_type_pun( actual_data );
     211           0 :     block_len = fd_solcap_write_stake_reward_event( ctx->capture_ctx->capture, msg_hdr, stake_reward_event );
     212           0 :     break;
     213           0 :   }
     214           0 :   case SOLCAP_STAKE_ACCOUNT_PAYOUT: {
     215           0 :     fd_solcap_stake_account_payout_t * stake_account_payout = fd_type_pun( actual_data );
     216           0 :     block_len = fd_solcap_write_stake_account_payout( ctx->capture_ctx->capture, msg_hdr, stake_account_payout );
     217           0 :     break;
     218           0 :   }
     219           0 :   default:
     220             :     /* Unknown signal received in message processing */
     221           0 :     FD_LOG_ERR(( "Unknown signal received in message processing: sig=%lu", (ulong)msg_hdr->sig ));
     222           0 :     break;
     223           0 :   }
     224           0 :   return block_len;
     225           0 : }
     226             : 
     227             : /* fd_capctx_buf_process_continuation processes continuation fragments
     228             :    (SOM=0) which contain raw data bytes to append to the current message.
     229             :    This is generic and works for any fragmented message type (account
     230             :    updates, or any future large message types). */
     231             : void
     232             : fd_capctx_buf_process_continuation( fd_solcap_tile_ctx_t * ctx,
     233             :                                     char *                 data,
     234           0 :                                     ulong                  data_sz ) {
     235           0 :   FD_TEST( ctx->capture_ctx->capture != NULL );
     236           0 :   fd_solcap_write_data( ctx->capture_ctx->capture, data, data_sz );
     237           0 : }
     238             : 
     239             : /* returnable_frag processes incoming message fragments and handles
     240             :    fragmented solcap messages using SOM (Start of Message) and EOM (End
     241             :    of Message) control flags.
     242             : 
     243             :    Message Fragmentation:
     244             :    ----------------------
     245             :    Solcap messages can be very large (up to 10MB for account data).  To
     246             :    avoid cache thrashing and fit within the ~4MB link size, large
     247             :    messages are split into smaller fragments of at most 128KB
     248             :    (SOLCAP_WRITE_ACCOUNT_DATA_MTU).
     249             : 
     250             :    SOM/EOM Control Flags:
     251             :    ----------------------
     252             :    Each fragment has two control flags set in the frag metadata:
     253             :    - SOM (Start of Message): Set on the first fragment of a message
     254             :    - EOM (End of Message):   Set on the last fragment of a message
     255             : 
     256             :    For a single-fragment message:
     257             :      Single Fragment:       SOM=1, EOM=1
     258             :    For a multi-fragment message:
     259             :      First fragment:        SOM=1, EOM=0
     260             :      Middle fragments:      SOM=0, EOM=0
     261             :      Last fragment:         SOM=0, EOM=1
     262             : 
     263             :    Fragment Processing:
     264             :    --------------------
     265             :    When SOM is set:
     266             :    - The fragment begins with a fd_solcap_buf_msg_t header containing
     267             :      the message type (sig), slot, and transaction index
     268             :    - This header is parsed and saved in the context (msg_set_sig,
     269             :      msg_set_slot)
     270             :    - The input link is locked (current_in_idx) to ensure all fragments
     271             :      of this message are processed sequentially from the same link
     272             :    - The actual data follows the header in the fragment
     273             :    - The PCAPNG block_len is calculated and saved (ctx->block_len) for
     274             :      use when writing the footer on EOM
     275             : 
     276             :    When SOM is not set (continuation fragment):
     277             :    - The entire fragment is data (no header)
     278             :    - The previously saved message state is used
     279             :    - No block_len is calculated (continuation data is appended)
     280             : 
     281             :    When EOM is set:
     282             :    - The PCAPNG block footer is written using the block_len from SOM
     283             :    - For bank preimage messages, the file is synced to disk
     284             :    - All message state is reset (msg_idx, block_len, msg_set_sig, etc.)
     285             :    - The input link is unlocked (current_in_idx = ULONG_MAX) to allow
     286             :      processing the next message
     287             : 
     288             :    This design allows the solcap tile to handle arbitrarily large
     289             :    messages while maintaining efficient memory usage and cache locality.
     290             : */
     291             : 
     292             : static inline int
     293             : returnable_frag( fd_solcap_tile_ctx_t * ctx,
     294             :                  ulong                  in_idx,
     295             :                  ulong                  seq    FD_PARAM_UNUSED,
     296             :                  ulong                  sig    FD_PARAM_UNUSED,
     297             :                  ulong                  chunk,
     298             :                  ulong                  sz,
     299             :                  ulong                  ctl,
     300             :                  ulong                  tsorig FD_PARAM_UNUSED,
     301             :                  ulong                  tspub  FD_PARAM_UNUSED,
     302           0 :                  fd_stem_context_t *    stem   FD_PARAM_UNUSED ) {
     303             : 
     304           0 :   if( FD_UNLIKELY( sz!=0UL && (chunk<ctx->in[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz>ctx->in[ in_idx ].mtu ) ) )
     305           0 :     FD_LOG_ERR(( "chunk %lu %lu from in %lu corrupt, not in range [%lu,%lu]", chunk, sz, in_idx, ctx->in[ in_idx ].chunk0, ctx->in[ in_idx ].wmark ));
     306             : 
     307             : 
     308             :   /* If we're processing a message from a different input, skip this
     309             :      fragment for now without incrementing input seq number */
     310           0 :   if( FD_UNLIKELY( ctx->current_in_idx != ULONG_MAX && ctx->current_in_idx != in_idx ) ) return 1;
     311             : 
     312           0 :   uchar const * data = fd_chunk_to_laddr_const( ctx->in[in_idx].mem, chunk );
     313             : 
     314           0 :   int som = fd_frag_meta_ctl_som( ctl );
     315           0 :   int eom = fd_frag_meta_ctl_eom( ctl );
     316             : 
     317           0 :   if( som ) {
     318           0 :     fd_solcap_buf_msg_t * msg_hdr = fd_type_pun( (void *)data );
     319           0 :     char * actual_data            = (char *)(data + sizeof(fd_solcap_buf_msg_t));
     320           0 :     FD_TEST( sz >= sizeof(fd_solcap_buf_msg_t) );
     321           0 :     ctx->msg_set_slot   = msg_hdr->slot;
     322           0 :     ctx->msg_set_sig    = (ushort)msg_hdr->sig;
     323           0 :     ctx->current_in_idx = in_idx;  /* Start tracking this input */
     324             : 
     325             :     /* Handle file rotation for recent_only mode */
     326           0 :     if( ctx->recent_only ) {
     327           0 :       if( ctx->recent_file_start_slot == ULONG_MAX ) {
     328           0 :         ctx->recent_file_start_slot = msg_hdr->slot;
     329           0 :       }
     330           0 :       else if( msg_hdr->slot >= ctx->recent_file_start_slot + ctx->recent_slots_per_file ) {
     331             :         /* Check if we need to rotate (>= slots_per_file slots from start) */
     332             :         /* Flip-flop to the other file */
     333           0 :         ulong next_idx = 1UL - ctx->recent_current_idx;
     334           0 :         int next_fd = ctx->recent_fds[next_idx];
     335             : 
     336             :         /* The following is a series of checks to ensure the file is
     337             :             synced and truncated correctly. This occurs via:
     338             :             1. Syncing the current file
     339             :             2. Syncing the next file
     340             :             3. Truncating the next file
     341             :             4. Resetting the file descriptor position to 0
     342             :             5. Reinitializing the solcap writer with the new file descriptor
     343             :         */
     344           0 :         FD_TEST( fsync( ctx->fd ) == 0 );
     345           0 :         FD_TEST( ftruncate( next_fd, 0L ) == 0 );
     346           0 :         FD_TEST( lseek( next_fd, 0L, SEEK_SET ) == 0L );
     347             : 
     348           0 :         fd_solcap_writer_init( ctx->capture_ctx->capture, next_fd );
     349           0 :         ctx->recent_current_idx = next_idx;
     350           0 :         ctx->recent_file_start_slot = msg_hdr->slot;
     351           0 :         ctx->fd = next_fd;
     352           0 :       }
     353           0 :     }
     354             : 
     355           0 :     uint block_len = fd_capctx_buf_process_som( ctx, msg_hdr, actual_data );
     356           0 :     FD_TEST( block_len > 0 );  /* SOM must return valid block length */
     357           0 :     ctx->block_len = block_len;
     358           0 :   } else {
     359             :     /* Continuation fragment: just raw data bytes */
     360           0 :     fd_capctx_buf_process_continuation( ctx, (char *)data, sz );
     361           0 :   }
     362             : 
     363             :   /* If message you receive has the eom flag, write footer */
     364           0 :   if( eom ) {
     365           0 :     FD_TEST( ctx->block_len > 0 );  /* Must have valid block length before writing footer */
     366           0 :     fd_solcap_write_ftr( ctx->capture_ctx->capture, ctx->block_len );
     367             : 
     368           0 :     ctx->msg_idx        = 0;
     369           0 :     ctx->block_len      = 0;
     370           0 :     ctx->msg_set_sig    = 0;
     371           0 :     ctx->msg_set_slot   = 0;
     372           0 :     ctx->current_in_idx = ULONG_MAX;  /* Reset to sentinel - ready for next message */
     373           0 :   } else {
     374           0 :     ctx->msg_idx++;
     375           0 :   }
     376             : 
     377           0 :   return 0;
     378           0 : }
     379             : 
     380             : static void
     381             : privileged_init( fd_topo_t *      topo,
     382           0 :                  fd_topo_tile_t * tile ) {
     383           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     384           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     385           0 :   fd_solcap_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_solcap_tile_ctx_t), sizeof(fd_solcap_tile_ctx_t) );
     386           0 :   void * _capture_ctx        = FD_SCRATCH_ALLOC_APPEND( l, fd_capture_ctx_align(),         fd_capture_ctx_footprint() );
     387             : 
     388           0 :   ctx->tile_idx = tile->kind_id;
     389             : 
     390           0 :   ctx->capture_ctx = fd_capture_ctx_join( fd_capture_ctx_new( _capture_ctx ) );
     391           0 :   FD_TEST( ctx->capture_ctx );
     392             : 
     393           0 :   ctx->recent_only = tile->solcap.recent_only;
     394           0 :   ctx->recent_slots_per_file = tile->solcap.recent_slots_per_file ? tile->solcap.recent_slots_per_file : 128UL;
     395             : 
     396           0 :   struct stat path_stat;
     397           0 :   int stat_result = stat( tile->solcap.solcap_capture, &path_stat );
     398             : 
     399           0 :   if( ctx->recent_only ) {
     400             :     /* recent_only=1: Ensure path is a directory, create if not exists */
     401           0 :     if( stat_result != 0 ) {
     402           0 :       if( FD_UNLIKELY( mkdir(tile->solcap.solcap_capture, 0755) != 0 ) ) {
     403           0 :         FD_LOG_ERR(( "solcap_recent_only=1 but could not create directory: %s (%i-%s)",
     404           0 :                    tile->solcap.solcap_capture, errno, strerror(errno) ));
     405           0 :       }
     406           0 :     } else if( FD_UNLIKELY( !S_ISDIR(path_stat.st_mode) ) ) {
     407           0 :       FD_LOG_ERR(( "solcap_recent_only=1 but path is not a directory: %s", tile->solcap.solcap_capture ));
     408           0 :     }
     409             : 
     410           0 :     ctx->recent_current_idx = 0;
     411           0 :     ctx->recent_file_start_slot = ULONG_MAX;  /* Will be set on first fragment */
     412             : 
     413           0 :     for( ulong i = 0; i < 2; i++ ) {
     414           0 :       char filepath[PATH_MAX];
     415           0 :       int ret = snprintf( filepath, PATH_MAX, "%s/recent_%lu.solcap", tile->solcap.solcap_capture, i );
     416           0 :       if( FD_UNLIKELY( ret<0 || ret>=PATH_MAX ) ) {
     417           0 :         FD_LOG_ERR(( "snprintf failed or path too long for recent file %lu", i ));
     418           0 :       }
     419             : 
     420           0 :       ctx->recent_fds[i] = open( filepath, O_RDWR | O_CREAT | O_TRUNC, 0644 );
     421           0 :       if( FD_UNLIKELY( ctx->recent_fds[i] == -1 ) ) {
     422           0 :         FD_LOG_ERR(( "failed to open or create solcap recent file %s (%i-%s)",
     423           0 :                      filepath, errno, strerror(errno) ));
     424           0 :       }
     425           0 :     }
     426             : 
     427           0 :     ctx->fd = ctx->recent_fds[0];
     428             : 
     429           0 :   } else {
     430             :     /* recent_only=0: Validate that path is a file*/
     431           0 :     if( FD_UNLIKELY( stat_result == 0 && S_ISDIR(path_stat.st_mode) ) ) {
     432           0 :       FD_LOG_ERR(( "solcap_recent_only=0 but path is a directory: %s (should be a file path)", tile->solcap.solcap_capture ));
     433           0 :     }
     434             : 
     435           0 :     ctx->fd = open( tile->solcap.solcap_capture, O_RDWR | O_CREAT | O_TRUNC, 0644 );
     436           0 :     if( FD_UNLIKELY( ctx->fd == -1 ) ) {
     437           0 :       FD_LOG_ERR(( "failed to open or create solcap capture file %s (%i-%s)",
     438           0 :                    tile->solcap.solcap_capture, errno, strerror(errno) ));
     439           0 :     }
     440           0 :   }
     441             : 
     442           0 :   FD_TEST( ctx->capture_ctx->capture );
     443             : 
     444           0 :   ctx->capture_ctx->solcap_start_slot = tile->solcap.capture_start_slot;
     445           0 :   fd_solcap_writer_init( ctx->capture_ctx->capture, ctx->fd );
     446             : 
     447           0 :   ctx->current_in_idx = ULONG_MAX;  /* No active message initially */
     448           0 :   ctx->msg_idx      = 0UL;
     449           0 :   ctx->msg_set_sig  = 0U;
     450           0 :   ctx->msg_set_slot = 0UL;
     451           0 :   ctx->block_len    = 0U;
     452             : 
     453           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
     454             : 
     455           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     456           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     457             : 
     458           0 : }
     459             : 
     460             : static void
     461             : unprivileged_init( fd_topo_t *      topo,
     462           0 :                    fd_topo_tile_t * tile ) {
     463             : 
     464           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     465           0 :   fd_solcap_tile_ctx_t * ctx = (fd_solcap_tile_ctx_t *)scratch;
     466             : 
     467           0 :   ctx->in_cnt = 0UL;
     468           0 :   FD_TEST( tile->in_cnt <= 32UL );
     469           0 :   for( ulong i = 0UL; i < tile->in_cnt; i++ ) {
     470           0 :     fd_topo_link_t * link = &topo->links[ tile->in_link_id[ i ] ];
     471           0 :     fd_topo_wksp_t * wksp = &topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ];
     472             : 
     473           0 :     ctx->in[ctx->in_cnt].mem    = wksp->wksp;
     474           0 :     ctx->in[ctx->in_cnt].chunk0 = fd_dcache_compact_chunk0( wksp->wksp, link->dcache );
     475           0 :     ctx->in[ctx->in_cnt].wmark  = fd_dcache_compact_wmark( wksp->wksp, link->dcache, link->mtu );
     476           0 :     ctx->in[ctx->in_cnt].mtu    = link->mtu;
     477           0 :     ctx->in_cnt++;
     478           0 :   }
     479           0 : }
     480             : 
     481           0 : #define STEM_BURST (1UL)
     482           0 : #define STEM_LAZY  (50UL)
     483             : 
     484           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_solcap_tile_ctx_t
     485           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_solcap_tile_ctx_t)
     486             : 
     487           0 : #define STEM_CALLBACK_RETURNABLE_FRAG returnable_frag
     488             : 
     489             : #include "../../disco/stem/fd_stem.c"
     490             : 
     491             : fd_topo_run_tile_t fd_tile_solcap = {
     492             :   .name                     = "solcap",
     493             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     494             :   .populate_allowed_fds     = populate_allowed_fds,
     495             :   .scratch_align            = scratch_align,
     496             :   .scratch_footprint        = scratch_footprint,
     497             :   .privileged_init          = privileged_init,
     498             :   .unprivileged_init        = unprivileged_init,
     499             :   .run                      = stem_run
     500             : };

Generated by: LCOV version 1.14