LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 29 29 100.0 %
Date: 2025-07-01 05:00:49 Functions: 74 5194 1.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_util_wksp_fd_wksp_h
       2             : #define HEADER_fd_src_util_wksp_fd_wksp_h
       3             : 
       4             : #include "../tpool/fd_tpool.h"
       5             : #include "../checkpt/fd_checkpt.h"
       6             : 
       7             : /* API for creating NUMA-aware and TLB-efficient workspaces used for
       8             :    complex inter-thread and inter-process shared memory communication
       9             :    patterns.  fd must be booted to use the APIs in this module.
      10             : 
      11             :    For example, startup scripts could reserve some memory on each NUMA
      12             :    node backed by huge and gigantic pages:
      13             : 
      14             :      sudo bin/fd_shmem_cfg alloc   8 gigantic 0 \
      15             :                            alloc   8 gigantic 1 \
      16             :                            alloc 256     huge 0 \
      17             :                            alloc 256     huge 1
      18             : 
      19             :    and then some of this memory could be formatted into fd_wksp for each
      20             :    NUMA node:
      21             : 
      22             :      bin/fd_shmem_ctl new my-wksp-numa-0 1 gigantic 0 \
      23             :                       new my-wksp-numa-1 1 gigantic 1
      24             : 
      25             :    Then, at application startup, processes can join these fd_wksp and
      26             :    concurrently allocate memory from the desired NUMA nodes as
      27             :    necessary.  E.g.
      28             : 
      29             :      fd_wksp_t * wksp = fd_wksp_attach( "my-wksp-numa-0" ); // logs details on failure
      30             :      if( !fd_wksp ) ... handle attach failure ...;
      31             : 
      32             :      ulong gaddr = fd_wksp_alloc( wksp, align, sz ); // logs details on failure
      33             :      if( !gaddr ) ... handle alloc failure ...;
      34             : 
      35             :    The local address of a workspace global address can be found via:
      36             : 
      37             :      void * laddr = fd_wksp_laddr( wksp, gaddr ); // logs details on failure
      38             :      if( !laddr ) ... handle bad (wksp,gaddr) ...;
      39             : 
      40             :    and the global address of a workspace local address can be found via:
      41             : 
      42             :      ulong gaddr = fd_wksp_gaddr( wksp, laddr ); // logs details on failure
      43             :      if( !gaddr ) ... handle bad (wksp,laddr) ...;
      44             : 
      45             :    Allocations can be freed via:
      46             : 
      47             :      fd_wksp_free( wksp, gaddr );
      48             : 
      49             :    Any join can free any allocation regardless of who made it.
      50             : 
      51             :    When the application is done using a wksp, it should leave it.  The
      52             :    workspace will continue to exist (it just is no longer safe to access
      53             :    in the caller's address space).  E.g.
      54             : 
      55             :      fd_wksp_detach( wksp ); // logs details on failure
      56             : 
      57             :    Likewise, if the workspaces are no longer in use, they can be deleted
      58             :    via something like:
      59             : 
      60             :      bin/fd_wksp_ctl delete my-wksp-numa-0 \
      61             :                      delete my-wksp-numa-1
      62             : 
      63             :    All allocations can be freed via something like:
      64             : 
      65             :      bin/fd_wksp_ctl reset my-wksp-numa-0 \
      66             :                      reset my-wksp-numa-1
      67             : 
      68             :    or in code:
      69             : 
      70             :      fd_wksp_reset( wksp, seed ); // logs details on failure
      71             : 
      72             :    It is the caller's responsibility to ensure that previous allocations
      73             :    to the wksp are not in use.
      74             : 
      75             :    Note: while this presents "aligned_alloc" style API semantics, this
      76             :    is not designed to be algorithmically optimal, HPC implementation or
      77             :    efficient at doing lots of tiny allocations.  Rather it is designed
      78             :    to be akin to an "mmap" / "sbrk" style allocator of last resort, done
      79             :    rarely and then ideally at application startup (e.g. setting up
      80             :    datastructures at box startup or used in an interprocess lockfree
      81             :    allocator as a mmap replacement).
      82             : 
      83             :    Instead, this tries to keep wksp fragmentation low with low overhead
      84             :    and tight packing of larger size allocations (normal page size and
      85             :    up).  It further tries to proactively limit the risk of heap
      86             :    _metadata_ corruption (proactive intraworkspace heap application
      87             :    _data_ corruption prevention is not a goal though typical mechanisms
      88             :    for such are in _direct_ opposition to efficient use of TLB, low
      89             :    fragmentation and tight allocation packing).  It is quasi-lockfree
      90             :    such that a process _killed_ in the middle of a workspace operation
      91             :    will not prevent other processes from using the workspace but a
      92             :    process _stalled_ in the middle of a workspace operations can stall
      93             :    other applications waiting to use the workspace indefinitely.
      94             :    Operators can track down an errant process stalled in the middle of
      95             :    workspace operations and blocking other processes).  Likewise
      96             :    detailed usage and metadata integrity checking and repair can be done
      97             :    via something like fd_wksp_ctl check / verify / rebuild / etc.
      98             :    Practically speaking, none of this really matters if usage occurs
      99             :    predominantly during application startup / shutdown.
     100             : 
     101             :    See below for more details. */
     102             : 
     103             : /* FD_WKSP_SUCCESS is used by various APIs to indicate an operation
     104             :    successfully completed.  This will be 0.  FD_WKSP_ERR_* gives a
     105             :    number of error codes used by fd_wksp APIs.  These will be negative
     106             :    integers. */
     107             : 
     108   997338804 : #define FD_WKSP_SUCCESS     (0)  /* Success */
     109          69 : #define FD_WKSP_ERR_INVAL   (-1) /* Failed due to obviously invalid inputs */
     110          81 : #define FD_WKSP_ERR_FAIL    (-2) /* Failed due to shared memory limitation */
     111   130251573 : #define FD_WKSP_ERR_CORRUPT (-3) /* Workspace memory corruption detected (potentially recoverable by rebuilding) */
     112             : 
     113             : /* FD_WKSP_{ALIGN,FOOTPRINT} describe the alignment and footprint of a
     114             :    fd_wksp_t.  ALIGN is a positive integer power of 2.  FOOTPRINT is a
     115             :    multiple of ALIGN.  FOOTPRINT assumes part_max and data_max are
     116             :    non-zero and small enough that the footprint will not overflow at
     117             :    most ULONG_MAX bytes.  These are provided to facilitate compile time
     118             :    declarations. */
     119             : 
     120        1770 : #define FD_WKSP_ALIGN (128UL)
     121             : #define FD_WKSP_FOOTPRINT( part_max, data_max )                                         \
     122             :   FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \
     123             :     FD_WKSP_ALIGN, 128UL           ), /* header */                                      \
     124             :     64UL,          64UL*(part_max) ), /* partition info */                              \
     125             :     1UL,           (data_max)+1UL  ), /* data region and footer */                      \
     126             :     FD_WKSP_ALIGN )                   /* tail padding */
     127             : 
     128             : /* FD_WKSP_ALIGN_DEFAULT gives the default alignments of a wksp
     129             :    allocation.  This is a positive integer power of two of at least 16
     130             :    (for malloc compatibility).  Additional details described in
     131             :    fd_wksp_alloc. */
     132             : 
     133    81666168 : #define FD_WKSP_ALIGN_DEFAULT (4096UL)
     134             : 
     135             : /* FD_WKSP_CSTR_MAX is the number of bytes maximum that can be in a wksp
     136             :    global address cstr. */
     137             : 
     138             : #define FD_WKSP_CSTR_MAX (FD_SHMEM_NAME_MAX + 21UL)
     139             : 
     140             : /* FD_WKSP_CHECKPT_STYLE_* specifies the streaming format to use for
     141             :    a workspace checkpoint.  These are non-zero.
     142             : 
     143             :      V1 - the stream will have extensive workspace metadata followed by
     144             :           the used workspace partitions.  No compression or hashing is
     145             :           done of the workspace partitions.
     146             : 
     147             :      V2 - similar to V1 in functionality but will be written such that
     148             :           checkpt and restore are parallelizable.
     149             : 
     150             :      V3 - This is actually V2 but compressed frames will be enabled.
     151             : 
     152             :      DEFAULT - the style to use when not specified by user.  0 indicates
     153             :      to use V3 if the target supports it and V2 if not. */
     154             : 
     155          63 : #define FD_WKSP_CHECKPT_STYLE_V1      (1)
     156         192 : #define FD_WKSP_CHECKPT_STYLE_V2      (2)
     157          84 : #define FD_WKSP_CHECKPT_STYLE_V3      (3)
     158             : 
     159             : #define FD_WKSP_CHECKPT_STYLE_DEFAULT (0)
     160             : 
     161             : #define FD_WKSP_CHECKPT_STYLE_RAW     FD_WKSP_CHECKPT_STYLE_V1 /* backward compat */
     162             : 
     163             : /* A fd_wksp_t * is an opaque handle of a workspace */
     164             : 
     165             : struct fd_wksp_private;
     166             : typedef struct fd_wksp_private fd_wksp_t;
     167             : 
     168             : /* A fd_wksp_usage_t is used to return workspace usage stats. */
     169             : 
     170             : struct fd_wksp_usage {
     171             :   ulong total_max;
     172             :   ulong total_cnt; ulong total_sz;
     173             :   ulong free_cnt;  ulong free_sz;
     174             :   ulong used_cnt;  ulong used_sz;
     175             : };
     176             : 
     177             : typedef struct fd_wksp_usage fd_wksp_usage_t;
     178             : 
     179             : FD_PROTOTYPES_BEGIN
     180             : 
     181             : /* Admin APIs *********************************************************/
     182             : 
     183             : /* It is rare to need to use the admin APIs directly (especially on a
     184             :    hosted system).  Recommend using the helper APIs below for most
     185             :    needs. */
     186             : 
     187             : /* Constructors */
     188             : 
     189             : /* fd_wksp_part_max_est computes an estimated maximum number of
     190             :    partitions for a workspace that needs to fit within footprint bytes
     191             :    and has sz_typical allocations typically.  Returns a positive value
     192             :    on success and 0 on failure.  Reasons for failure include footprint
     193             :    too small, sz_typical is 0 and sz_typical is so large that footprint
     194             :    has no room for metadata anyway.  Useful for determining how to pack
     195             :    a workspace tightly into a known footprint region. */
     196             : 
     197             : FD_FN_CONST ulong
     198             : fd_wksp_part_max_est( ulong footprint,
     199             :                       ulong sz_typical );
     200             : 
     201             : /* fd_wksp_data_max_est computes an estimated maximum data region size
     202             :    for footprint sized workspace with part_max partitions.  Returns a
     203             :    positive value on success and 0 on failure.  Reasons for failure
     204             :    include footprint is too small, part_max is 0, part_max is too large
     205             :    for under the hood implementation limitations or part_max is too
     206             :    large to have a non-zero sized data region.  Useful for determining
     207             :    how to pack a workspace into a known footprint region. */
     208             : 
     209             : FD_FN_CONST ulong
     210             : fd_wksp_data_max_est( ulong footprint,
     211             :                       ulong part_max );
     212             : 
     213             : /* fd_wksp_{align,footprint} give the required alignment and footprint
     214             :    for a workspace that can support up to part_max partitions and with a
     215             :    data region of data_max bytes.  fd_wksp_align returns FD_WKSP_ALIGN.
     216             :    fd_wksp_footprint(part_max,data_max) returns
     217             :    FD_WKSP_FOOTPRINT(part_max,data_max) on success and 0 on failure.
     218             :    Reasons for failure include zero part_max, part_max too large for
     219             :    this implementation, zero data_max, part_max/data_max requires a
     220             :    footprint that overflows a ULONG_MAX. */
     221             : 
     222             : FD_FN_CONST ulong
     223             : fd_wksp_align( void );
     224             : 
     225             : FD_FN_CONST ulong
     226             : fd_wksp_footprint( ulong part_max,
     227             :                    ulong data_max );
     228             : 
     229             : /* fd_wksp_new formats an unused memory region with the appropriate
     230             :    footprint and alignment mapped into the caller's address space at
     231             :    shmem into a wksp with given name (should be a valid fd_shmem name
     232             :    and will match the underlying shared memory region name / anonymous
     233             :    join for a wksp created via the shmem helpers below).  seed is the
     234             :    arbitrary value used to seed the heap priorities under the hood.
     235             :    Returns NULL on failure (logs details) or shmem on success.  The
     236             :    caller is _not_ joined on return. */
     237             : 
     238             : void *
     239             : fd_wksp_new( void *       shmem,
     240             :              char const * name,
     241             :              uint         seed,
     242             :              ulong        part_max,
     243             :              ulong        data_max );
     244             : 
     245             : /* fd_wksp_join joins a workspace.  shwksp is the location of the where
     246             :    the wksp has been mapped into the caller's address space.  Returns
     247             :    the local handle of the join on success or NULL on failure (logs
     248             :    details).  The caller can read / write memory in the joined workspace
     249             :    on return (a caller can do a read only join by mapping the shwksp
     250             :    into the local address as read only).  There is no practical
     251             :    limitation on the number of concurrent joins in a thread, process or
     252             :    system wide.*/
     253             : 
     254             : fd_wksp_t *
     255             : fd_wksp_join( void * shwksp );
     256             : 
     257             : /* fd_wksp_leave leaves a workspace.  Returns shwksp on success and NULL
     258             :    on failure (logs details).  The caller should not continue to read or
     259             :    write any memory for the join on return but the workspace will
     260             :    continue to exist. */
     261             : 
     262             : void *
     263             : fd_wksp_leave( fd_wksp_t * wksp );
     264             : 
     265             : /* fd_wksp_delete unformats a memory region used as a workspace.
     266             :    Returns the shmem on pointer on success and NULL on failure (logs
     267             :    details).  There should not be anybody joined to the workspace when
     268             :    it is deleted. */
     269             : 
     270             : void *
     271             : fd_wksp_delete( void * shwksp );
     272             : 
     273             : /* Accessors */
     274             : 
     275             : /* fd_wksp_name a cstr pointer to the wksp name (will point to a valid
     276             :    region name, e.g. strlen( name ) in [1,FD_SHMEM_NAME_MAX)).  Assumes
     277             :    wksp is a valid current join.  Lifetime of the returned string is the
     278             :    lifetime of the join.  The pointer value is const and the string
     279             :    pointed at is const for the lifetime of join.
     280             : 
     281             :    fd_wksp_seed returns the seed used at creation / most recent rebuild.
     282             :    Assumes wksp is a current local join.
     283             : 
     284             :    fd_wksp_{part_max,data_max} returns {part_max,data_max} used at
     285             :    creation.  Assumes wksp is a current local join. */
     286             : 
     287             : FD_FN_CONST char const * fd_wksp_name    ( fd_wksp_t const * wksp );
     288             : FD_FN_PURE  uint         fd_wksp_seed    ( fd_wksp_t const * wksp );
     289             : FD_FN_PURE  ulong        fd_wksp_part_max( fd_wksp_t const * wksp );
     290             : FD_FN_PURE  ulong        fd_wksp_data_max( fd_wksp_t const * wksp );
     291             : 
     292             : /* fd_wksp_owner returns the id of the thread group that was currently
     293             :    in a wksp operation (0 indicates the wksp was in the process of being
     294             :    constructed) or ULONG_MAX if there was no operation in progress on
     295             :    the workspace.  Assumes wksp is a current local join.  The value will
     296             :    correspond to some point of time between when the call was made and
     297             :    the call returned. */
     298             : 
     299             : ulong fd_wksp_owner( fd_wksp_t const * wksp );
     300             : 
     301             : /* Misc */
     302             : 
     303             : /* fd_wksp_strerror converts an FD_WKSP_SUCCESS / FD_WKSP_ERR_* code
     304             :    into a human readable cstr.  The lifetime of the returned pointer is
     305             :    infinite.  The returned pointer is always to a non-NULL cstr. */
     306             : 
     307             : FD_FN_CONST char const *
     308             : fd_wksp_strerror( int err );
     309             : 
     310             : /* fd_wksp_verify does extensive verification of wksp.  Returns
     311             :    FD_WKSP_SUCCESS (0) if there are no issues detected with the wksp or
     312             :    FD_WKSP_ERR_CORRUPT (negative) otherwise (logs details).  wksp is a
     313             :    current local join to a workspace.  This is used internally for
     314             :    verifying the integrity of a workspace if a caller detects in an
     315             :    operation that another caller died in the middle of a wksp operation.
     316             :    Users typically do not need to call this but it can be useful in
     317             :    debugging and testing.
     318             : 
     319             :    IMPORTANT SAFETY TIP!  This assumes there are no concurrent
     320             :    operations on wksp. */
     321             : 
     322             : int
     323             : fd_wksp_verify( fd_wksp_t * wksp );
     324             : 
     325             : /* fd_wksp_rebuilds a wksp.  This is used internally for rebuilding
     326             :    workspace when a caller detects that another caller died in the
     327             :    middle of an alloc or free and left the workspace in an inconsistent
     328             :    state.  Returns FD_WKSP_SUCCESS (0) if wksp was rebuilt successfully
     329             :    or a FD_WKSP_ERR_CORRUPT (negative) if it could not (logs details).
     330             : 
     331             :    Rebuilding operates under the principle of "do no harm".
     332             :    Specifically, rebuilding does not impact any completed wksp
     333             :    allocations (even when it fails).  It can either complete or rollback
     334             :    any partially complete alloc / free depends on far along the partial
     335             :    operation was.
     336             : 
     337             :    Rebuilding should be always possible outside of actual memory
     338             :    corruption or code bug.  The main reason for failure is overlapping
     339             :    allocations were discovered during the rebuild (which would either be
     340             :    caused by memory corruption or a bug).
     341             : 
     342             :    Users typically do not need to call this but it can be useful as a
     343             :    weak form of ASLR by changing up the seed.  This is not a fast
     344             :    operation.
     345             : 
     346             :    IMPORTANT SAFETY TIP!  This assumes there are no concurrent
     347             :    operations on wksp. */
     348             : 
     349             : int
     350             : fd_wksp_rebuild( fd_wksp_t * wksp,
     351             :                  uint        seed );
     352             : 
     353             : /* User APIs **********************************************************/
     354             : 
     355             : /* fd_wksp_laddr map a wksp global address (an address all joiners
     356             :    agree upon) to the caller's local address space.  Invalid global
     357             :    addresses and/or 0UL will map to NULL (logs details if invalid).
     358             :    Assumes wksp is a current local join (NULL returns NULL). */
     359             : 
     360             : void *
     361             : fd_wksp_laddr( fd_wksp_t const * wksp,
     362             :                ulong             gaddr );
     363             : 
     364             : /* fd_wksp_gaddr maps a wksp local address to the corresponding wksp
     365             :    global address (an address all joiners agree upon).  Invalid local
     366             :    addresses and/or NULL will map to 0UL (logs details if invalid).
     367             :    Assumes wksp is a current local join (NULL returns NULL). */
     368             : 
     369             : ulong
     370             : fd_wksp_gaddr( fd_wksp_t const * wksp,
     371             :                void const *      laddr );
     372             : 
     373             : /* fd_wksp_gaddr_fast converts a laddr into a gaddr under the assumption
     374             :    wksp is a current local join and laddr is non-NULL local address in
     375             :    the wksp. */
     376             : 
     377             : FD_FN_CONST static inline ulong
     378             : fd_wksp_gaddr_fast( fd_wksp_t const * wksp,
     379    28015000 :                     void const *      laddr ) {
     380    28015000 :   return (ulong)laddr - (ulong)wksp;
     381    28015000 : }
     382             : 
     383             : /* fd_wksp_laddr_fast converts a gaddr into a laddr under the assumption
     384             :    wksp is a current local join and gaddr is non-NULL. */
     385             : 
     386             : FD_FN_CONST static inline void *
     387             : fd_wksp_laddr_fast( fd_wksp_t const * wksp,
     388   410470759 :                     ulong             gaddr ) {
     389   410470759 :   return (void *)((ulong)wksp + gaddr);
     390   410470759 : }
     391             : 
     392             : /* fd_wksp_alloc_at_least allocates at least sz bytes from wksp with
     393             :    an alignment of at least align (align must be a non-negative integer
     394             :    power-of-two or 0, which indicates to use the default alignment
     395             :    FD_WKSP_ALIGN_DEFAULT).  The allocation will be tagged with a
     396             :    positive value tag.  Returns the fd_wksp global address of the join
     397             :    on success and "NULL" (0UL) on failure (logs details).  A zero sz
     398             :    returns "NULL" (silent).  On return, [*lo,*hi) will contain the
     399             :    actually gaddr range allocated.  On success, [*lo,*hi) will overlap
     400             :    completely [ret,ret+sz) and ret will be aligned to requested
     401             :    alignment.  Assumes lo and hi are non-NULL.
     402             : 
     403             :    fd_wksp_alloc is a simple wrapper around fd_wksp_alloc_at_least for
     404             :    use when applications do not care about details of the actual
     405             :    allocated region.
     406             : 
     407             :    Note that fd_wksp_alloc / fd_wksp_free are not HPC implementations.
     408             :    Instead, these are designed to be akin to a mmap / sbrk allocator of
     409             :    "last resort" under the hood in other allocators like fd_alloc.  As
     410             :    such it prioritizes packing efficiency (best fit with arbitrary sizes
     411             :    and alignments allowed) over algorithmic efficiency (e.g.
     412             :    O(lg wksp_alloc_cnt) instead of O(1) like fd_alloc) and prioritize
     413             :    robustness against heap corruption (e.g. overrunning an allocation
     414             :    might corrupt the data in other allocations but will not corrupt the
     415             :    heap structure ... as the goal of this data structure is to encourage
     416             :    minimization of TLB usage, there is very little that can be done to
     417             :    proactively prevent intraworkspace interallocation data corruption).
     418             : 
     419             :    These operations are "quasi-lock-free".  Specifically, while they can
     420             :    suffer priority inversion due to a slow thread stalling other threads
     421             :    from using these operations, a process that is terminated in the
     422             :    middle of these operations leaves the wksp in a recoverable state.
     423             :    The only risk is the same risk generally from any application that
     424             :    uses persistent resources: applications that are terminated abruptly
     425             :    might leave allocations in the wksp that would have been freed had
     426             :    the application terminated normally.  As the allocator has no way to
     427             :    tell the difference between such allocations and allocations that are
     428             :    intended to outlive the application, it is the caller's
     429             :    responsibility to clean up such (allocation tagging can help greatly
     430             :    simplify this for users).  It would be possible to widen this API for
     431             :    applications to explicitly signal this intent and automatically clean
     432             :    up allocations not meant to outlive their creator but the general use
     433             :    here is expected to be long lived allocations.
     434             : 
     435             :    Priority inversion is not expected to be an issue practically as the
     436             :    expected use case is at app startup (some non-latency critical
     437             :    processes will do a handful of wksp operations to setup workspaces
     438             :    for applications on that box going forward and then the allocations
     439             :    will not be used again until the wksp is tore down / reset / etc).
     440             :    The remaining cases (e.g. a fine grained allocator like fd_alloc
     441             :    needs to procure more memory from the workspace) are expected to be
     442             :    rare enough that the O(lg N) costs still will be more than adequate.
     443             :    Note further that fd_alloc allows very fast interprocess allocations
     444             :    to be done by using a wksp as an allocator of last resort (in such,
     445             :    all allocations would be strictly lock free unless they needed to
     446             :    invoke this allocator, as is typically the case in other lock free
     447             :    allocators).
     448             : 
     449             :    Likewise, operations do extensive allocation metadata integrity
     450             :    checks to facilitate robust persistent usage.  If there is metadata
     451             :    data corruption detected (e.g. hardware fault, code corruption, etc),
     452             :    there are fsck-like APIs to rebuild wksp metadata.  Data integrity
     453             :    protection is more defined by the application.
     454             : 
     455             :    Tags are application specific.  They can allow manual and automated
     456             :    processes to do various debugging, diagnostics, analytics and garbage
     457             :    collection on a workspace (e.g. superblocks from a fd_alloc can be
     458             :    tagged specifically for that fd_alloc to allow memory leaks in
     459             :    general to be detected at program termination with no additional
     460             :    overheads and allow such leaks cleaned up via tagged frees).
     461             :    Notably, tags are wide enough to encode gaddrs.  This opens up the
     462             :    possibly for filesystem-like complex metadata operations.
     463             : 
     464             :    IMPORTANT!  align technically refers to the alignment in the wksp's
     465             :    global address space.  As such, wksp must be mmaped into each local
     466             :    address space with an alignment of at least the largest alignment the
     467             :    overall application intends to use.  Common practices automatically
     468             :    satisfy this (e.g. if wksp is backed by normal/huge/gigantic pages
     469             :    and only asks for alignments of at most a normal/huge/gigantic page
     470             :    sz, this constraint is automatically satisfied as fd_shmem_join needs
     471             :    to mmap wksp into the local address space with normal/huge/gigantic
     472             :    alignment anyway).  If doing more exotic things (e.g. backing wksp by
     473             :    normal pages but requiring much larger alignments), explicitly
     474             :    specifying the wksp virtual address location (e.g. in the
     475             :    fd_shmem_join call) might be necessary to satisfy this constraint.
     476             : 
     477             :    This implementation support arbitrary sz and align efficiently but
     478             :    each allocation will use up 1-3 wksp partitions to achieve this.  As
     479             :    these are a finite resources (and typically sized for a wksp that
     480             :    handles primarily larger allocations, like a fd_alloc huge
     481             :    superblock) and as there are allocators like fd_alloc that faster are
     482             :    algorithmically, lower overhead and lockfree O(1) for small sizes and
     483             :    alignment, it is strongly recommended to use this as an allocator of
     484             :    last resort and/or use this for larger chunkier allocations at
     485             :    application startup (e.g. sz + align >>> cache line).  An allocator
     486             :    like fd_alloc can then manage most allocations, falling back on this
     487             :    only when necessary. */
     488             : 
     489             : ulong
     490             : fd_wksp_alloc_at_least( fd_wksp_t * wksp,
     491             :                         ulong       align,
     492             :                         ulong       sz,
     493             :                         ulong       tag,
     494             :                         ulong *     lo,
     495             :                         ulong *     hi );
     496             : 
     497             : static inline ulong
     498             : fd_wksp_alloc( fd_wksp_t * wksp,
     499             :                ulong       align,
     500             :                ulong       sz,
     501       10320 :                ulong       tag ) {
     502       10320 :   ulong dummy[2];
     503       10320 :   return fd_wksp_alloc_at_least( wksp, align, sz, tag, dummy, dummy+1 );
     504       10320 : }
     505             : 
     506             : /* fd_wksp_free frees a wksp allocation.  gaddr is a global address that
     507             :    points to any byte in the allocation to free (i.e. can point to
     508             :    anything in of the gaddr range [*lo,*hi) returned by
     509             :    fd_wksp_alloc_at_least).  Logs details of any weirdness detected.
     510             :    Free of "NULL" (0UL) silently returns.  There are no restrictions on
     511             :    which join might free an allocation.  See note above other details. */
     512             : 
     513             : void
     514             : fd_wksp_free( fd_wksp_t * wksp,
     515             :               ulong       gaddr );
     516             : 
     517             : /* fd_wksp_tag returns the tag associated with an allocation.  gaddr
     518             :    is a wksp global address that points to any byte in the allocation.
     519             :    This is a fast O(lg wksp_alloc_cnt).  A return of 0 indicates that
     520             :    gaddr did not point into an allocation at some point in time between
     521             :    when this function was called until when it returned (this includes
     522             :    the cases when wksp is NULL and/or gaddr is 0).  This function is
     523             :    silent to facilitate integration with various analysis tools. */
     524             : 
     525             : ulong
     526             : fd_wksp_tag( fd_wksp_t * wksp,
     527             :              ulong       gaddr );
     528             : 
     529             : /* fd_wksp_tag_query queries the workspace for all partitions that match
     530             :    one of the given tags.  The tag array is indexed [0,tag_cnt).
     531             :    Returns info_cnt, the number of matching partitions.  Further, if
     532             :    info_max is non-zero, will return detailed information for the first
     533             :    (from low to high gaddr) min(info_cnt,info_max).  Returns 0 if no
     534             :    partitions match any tags.  If any wonkiness encountered (e.g. wksp
     535             :    is NULL, tag is not in positive, etc) returns 0 and logs details.
     536             :    This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
     537             :    O(wksp_alloc_cnt) with some additional work). */
     538             : 
     539             : struct fd_wksp_tag_query_info {
     540             :   ulong gaddr_lo; /* Partition covers workspace global addresses [gaddr_lo,gaddr_hi) */
     541             :   ulong gaddr_hi; /* 0<gaddr_lo<gaddr_hi */
     542             :   ulong tag;      /* Partition tag */
     543             : };
     544             : 
     545             : typedef struct fd_wksp_tag_query_info fd_wksp_tag_query_info_t;
     546             : 
     547             : ulong
     548             : fd_wksp_tag_query( fd_wksp_t *                wksp,
     549             :                    ulong const *              tag,
     550             :                    ulong                      tag_cnt,
     551             :                    fd_wksp_tag_query_info_t * info,
     552             :                    ulong                      info_max );
     553             : 
     554             : /* fd_wksp_tag_free frees all allocations in wksp that match one of the
     555             :    given tags.  The tag array is indexed [0,tag_cnt).  Logs details if
     556             :    any wonkiness encountered (e.g. wksp is NULL, tag is not in positive.
     557             :    This is O(wksp_alloc_cnt*tag_cnt) currently (but could be made
     558             :    O(wksp_alloc_cnt) with some additional work). */
     559             : 
     560             : void
     561             : fd_wksp_tag_free( fd_wksp_t *   wksp,
     562             :                   ulong const * tag,
     563             :                   ulong         tag_cnt );
     564             : 
     565             : /* fd_wksp_memset sets all bytes in a wksp allocation to character c.
     566             :    gaddr is a global address that points to any byte in the allocation
     567             :    (i.e. can point to anything in range returned by
     568             :    fd_wksp_alloc_at_least and will fill the whole range).  Logs details
     569             :    of any weirdness detected.  Clear of "NULL" (0UL) silently returns.
     570             :    Atomic with respect to other operations on this workspace. */
     571             : 
     572             : void
     573             : fd_wksp_memset( fd_wksp_t * wksp,
     574             :                 ulong       gaddr,
     575             :                 int         c );
     576             : 
     577             : /* fd_wksp_reset frees all allocations from the wksp.  Logs details on
     578             :    failure. */
     579             : 
     580             : void
     581             : fd_wksp_reset( fd_wksp_t * wksp,
     582             :                uint        seed );
     583             : 
     584             : /* fd_wksp_usage computes the wksp usage at some point in time between
     585             :    when the call was made and the call returned, populating the user
     586             :    provided usage structure with the result.  Always returns usage.
     587             : 
     588             :    wksp is a current local join to the workspace to compute usage.
     589             : 
     590             :    tag[tag_idx] for tag_idx in [0,tag_cnt) is an array of tags to
     591             :    compute the usage.  The order doesn't matter and, if a tag appears
     592             :    multiple times in the array, it will be counted once in the used
     593             :    stats.  A zero tag_cnt (potentially with a NULL tag) is fine
     594             :    (used_cnt,used_set for such will be 0,0).  A tag of 0 indicates to
     595             :    include free partitions in the used stats.
     596             : 
     597             :    total_max is the maximum partitions the wksp can have.  This will be
     598             :    positive (==part_max).
     599             : 
     600             :    total_sz is the number of bytes the wksp has available for
     601             :    partitioning (==data_max).  As the partitioning always covers the
     602             :    entire wksp, total_sz is constant for the lifetime of the wksp.
     603             : 
     604             :    total_cnt is the number of partitions the wksp currently has.  This
     605             :    will be in [1,total_max].
     606             : 
     607             :    free_cnt/sz is the number of free partitions / free bytes the wksp
     608             :    currently has.  A free partition has a tag of 0 and is currently
     609             :    available for splitting to satisfy the a future fd_wksp_alloc
     610             :    request.
     611             : 
     612             :    used_cnt/sz is the number of partitions / bytes used by wksp
     613             :    partitions whose tags match those in the provided tag set.
     614             : 
     615             :    This is O(wksp_alloc_cnt*tag_cnt) and will lock the wksp while
     616             :    running (and potentially block the caller if others are holding onto
     617             :    the lock).  So use in testing, etc.  Likewise, the precise meaning of
     618             :    the statistics computed by this API are dependent on the
     619             :    implementation details under the hood (that is do not be surprised if
     620             :    this API gets changed in the future). */
     621             : 
     622             : fd_wksp_usage_t *
     623             : fd_wksp_usage( fd_wksp_t *       wksp,
     624             :                ulong const *     tag,
     625             :                ulong             tag_cnt,
     626             :                fd_wksp_usage_t * usage );
     627             : 
     628             : /* shmem APIs *********************************************************/
     629             : 
     630             : /* fd_wksp_new_named creates a shared memory region named name and
     631             :    formats as a workspace.  Ignoring error trapping, this is a shorthand
     632             :    for:
     633             : 
     634             :      // Size the workspace to use all the memory
     635             :      ulong footprint = sum( sub_page_cnt[*] )*page_sz
     636             :      ulong part_max  = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
     637             :      ulong data_max  = fd_wksp_data_max_est( footprint, part_max );
     638             : 
     639             :      // Create the shared memory region and format as a workspace
     640             :      fd_shmem_create_multi( name, page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx, mode );
     641             :      void * shmem = fd_shmem_join( name, FD_SHMEM_JOIN_MODE_READ_WRITE, NULL, NULL, NULL ) );
     642             :      fd_wksp_new( shmem, name, seed, part_max, data_max );
     643             :      fd_shmem_leave( shmem, NULL, NULL );
     644             : 
     645             :    The 64 KiB above is where fd_alloc currently transitions to directly
     646             :    allocating from the wksp.
     647             : 
     648             :    Returns FD_WKSP_SUCCESS (0) on success and an FD_WKSP_ERR_*
     649             :    (negative) on failure (logs details).  Reasons for failure include
     650             :    INVAL (user arguments obviously bad) and FAIL (could not procure or
     651             :    format the shared memory region). */
     652             : 
     653             : int
     654             : fd_wksp_new_named( char const *  name,
     655             :                    ulong         page_sz,
     656             :                    ulong         sub_cnt,
     657             :                    ulong const * sub_page_cnt,
     658             :                    ulong const * sub_cpu_idx,
     659             :                    ulong         mode,
     660             :                    uint          seed,
     661             :                    ulong         opt_part_max );
     662             : 
     663             : /* fd_wksp_delete_named deletes a workspace created with
     664             :    fd_wksp_new_named.  There should not be any other joins / attachments
     665             :    to wksp when this is called.  Returns FD_WKSP_SUCCESS (0) on success
     666             :    and FD_WKSP_ERR_* (negative) on failure (logs details). */
     667             : 
     668             : int
     669             : fd_wksp_delete_named( char const * name );
     670             : 
     671             : /* fd_wksp_new_anon creates a workspace local to this thread group that
     672             :    otherwise looks and behaves _exactly_ like a workspace shared between
     673             :    multiple thread groups on this host of the same name, TLB and NUMA
     674             :    properties.  Ignoring error trapping, this is a shorthand for:
     675             : 
     676             :      // Size the workspace to use all the memory
     677             :      ulong page_cnt  = sum( sub_page_cnt[*] );
     678             :      ulong footprint = page_cnt*page_sz;
     679             :      ulong part_max  = opt_part_max ? opt_part_max : fd_wksp_part_max_est( footprint, 64 KiB );
     680             :      ulong data_max  = fd_wksp_data_max_est( footprint, part_max );
     681             : 
     682             :      // Create the anonymous memory region and format as a workspace
     683             :      void * mem = fd_shmem_acquire_multi( page_sz, sub_cnt, sub_page_cnt, sub_cpu_idx );
     684             :      fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) );
     685             :      fd_shmem_join_anonymous( name, FD_SHMEM_JOIN_MODE_READ_WRITE, wksp, mem, page_sz, page_cnt );
     686             : 
     687             :    There should be must no current shmem joins to name and the anonymous
     688             :    join will shadow any preexisting fd_shmem region with the same name
     689             :    in the calling thread group).  Returns the joined workspace on
     690             :    success and NULL on failure (logs details).  The final leave and
     691             :    delete to this workspace should be through fd_wksp_delete_anon. */
     692             : 
     693             : fd_wksp_t *
     694             : fd_wksp_new_anon( char const *  name,
     695             :                   ulong         page_sz,
     696             :                   ulong         sub_cnt,
     697             :                   ulong const * sub_page_cnt,
     698             :                   ulong const * sub_cpu_idx,
     699             :                   uint          seed,
     700             :                   ulong         opt_part_max );
     701             : 
     702             : /* fd_wksp_delete_anon deletes a workspace created with fd_wksp_new_anon
     703             :    There should not be any other joins / attachments to wksp when this
     704             :    is called.  This cannot fail from the caller's POV; logs details if
     705             :    any wonkiness is detected during the delete. */
     706             : 
     707             : void
     708             : fd_wksp_delete_anon( fd_wksp_t * wksp );
     709             : 
     710             : /* TODO: eliminate these legacy versions of the in favor of the above. */
     711             : 
     712             : static inline fd_wksp_t *
     713             : fd_wksp_new_anonymous( ulong         page_sz,
     714             :                        ulong         page_cnt,
     715             :                        ulong         cpu_idx,
     716             :                        char const *  name,
     717          72 :                        ulong         opt_part_max ) {
     718          72 :   return fd_wksp_new_anon( name, page_sz, 1UL, &page_cnt, &cpu_idx, 0U, opt_part_max );
     719          72 : }
     720             : 
     721          48 : static inline void fd_wksp_delete_anonymous( fd_wksp_t * wksp ) { fd_wksp_delete_anon( wksp ); }
     722             : 
     723             : /* fd_wksp_attach attach to the workspace held by the shared memory
     724             :    region with the given name.  If there are regions with the same name
     725             :    backed by different page sizes, defaults to the region backed by the
     726             :    largest page size.  Returns wksp on success and NULL on failure
     727             :    (details are logged).  Multiple attachments within are fine (all but
     728             :    the first attachment will be a reasonably fast O(1) call); all
     729             :    attachments in a process will use the same local fd_wksp_t handle.
     730             :    Every attach should be paired with a detach.  TODO: CONST-VARIANTS? */
     731             : 
     732             : fd_wksp_t *
     733             : fd_wksp_attach( char const * name );
     734             : 
     735             : /* fd_wksp_detach detaches from the given workspace.  All but the last
     736             :    detach should be a reasonably fast O(1) call.  Returns non-zero on
     737             :    failure. */
     738             : 
     739             : int
     740             : fd_wksp_detach( fd_wksp_t * wksp );
     741             : 
     742             : /* fd_wksp_containing maps a fd_wksp local addr to the corresponding
     743             :    fd_wksp local join.  Returns NULL if laddr does not appear to be from
     744             :    a locally joined fd_wksp.  Always silent such that this can be used
     745             :    to detect if a pointer is from a fd_wksp or not.  This is not a
     746             :    terribly fast call.  This API can only be used on laddrs in wksp are
     747             :    either named or anonymous workspaces. */
     748             : 
     749             : fd_wksp_t *
     750             : fd_wksp_containing( void const * laddr );
     751             : 
     752             : /* fd_wksp_alloc_laddr is the same as fd_wksp_alloc but returns a
     753             :    pointer in the caller's local address space if the allocation was
     754             :    successful (and NULL if not).  Ignoring error trapping, this is a
     755             :    shorthand for:
     756             : 
     757             :      fd_wksp_laddr( wksp, fd_wksp_alloc( wksp, align, sz, tag ) ) */
     758             : 
     759             : void *
     760             : fd_wksp_alloc_laddr( fd_wksp_t * wksp,
     761             :                      ulong       align,
     762             :                      ulong       sz,
     763             :                      ulong       tag );
     764             : 
     765             : /* fd_wksp_free_laddr is the same as fd_wksp_free but takes a pointer
     766             :    in the caller's local address space into a workspace allocation.
     767             :    Ignoring error trapping, this is a shorthand for:
     768             : 
     769             :      fd_wksp_t * wksp = fd_wksp_containing( laddr );
     770             :      fd_wksp_free( wksp, fd_wksp_gaddr( wksp, laddr ) );
     771             : 
     772             :    This API can only be used on laddrs in wksp are either named or
     773             :    anonymous workspaces. */
     774             : 
     775             : void
     776             : fd_wksp_free_laddr( void * laddr );
     777             : 
     778             : /* cstr helper APIs ***************************************************/
     779             : 
     780             : /* Overall, these are meant for use at application startup / shutdown
     781             :    and not in critical loops. */
     782             : 
     783             : /* fd_wksp_cstr prints the wksp global address gaddr into cstr as a
     784             :    [fd_wksp_name(wksp)]:[gaddr].  Caller promises that cstr has room for
     785             :    FD_WKSP_CSTR_MAX bytes.  Returns cstr on success and NULL on failure
     786             :    (logs details).  Reasons for failure include NULL wksp, gaddr not in
     787             :    the data region (or one past), NULL cstr. */
     788             : 
     789             : char *
     790             : fd_wksp_cstr( fd_wksp_t const * wksp,
     791             :               ulong             gaddr,
     792             :               char *            cstr );
     793             : 
     794             : /* fd_wksp_cstr_laddr is the same fd_wksp_cstr but takes a pointer in
     795             :    the caller's local address space to a wksp location.  Ignoring error
     796             :    trapping, this is a shorthand for:
     797             : 
     798             :      fd_wksp_t * wksp = fd_wksp_containing( laddr );
     799             :      return fd_wksp_cstr( wksp, fd_wksp_gaddr( wksp, laddr ), cstr );
     800             : 
     801             :    Returns NULL if laddr does not point strictly inside a workspace
     802             :    (logs details).  This API can only be used on laddrs in wksp are
     803             :    either named or anonymous workspaces. */
     804             : 
     805             : char *
     806             : fd_wksp_cstr_laddr( void const * laddr,
     807             :                     char *       cstr );
     808             : 
     809             : /* fd_wksp_cstr_alloc allocates sz bytes with alignment align from name
     810             :    or anonymous wksp with name.  align and sz have the exact same
     811             :    semantics as fd_wksp_alloc.  cstr must be non-NULL with space for up
     812             :    to FD_WKSP_CSTR_MAX bytes.
     813             : 
     814             :    Returns cstr on success and NULL on failure (logs details).  On
     815             :    success, cstr will contain a [name]:[gaddr] string suitable for use
     816             :    by fd_wksp_map and fd_wksp_cstr_free.  cstr will be untouched
     817             :    otherwise.  Ignoring error trapping, this is a shorthand for:
     818             : 
     819             :      fd_wksp_t * wksp  = fd_wksp_attach( name );
     820             :      ulong       gaddr = fd_wksp_alloc( wksp, align, sz );
     821             :      fd_wksp_detach( wksp );
     822             :      sprintf( cstr, "%s:%lu", name, gaddr );
     823             :      return cstr;
     824             : 
     825             :    As such, if doing many allocations from the same wksp, it is faster
     826             :    to do a fd_wksp_attach upfront, followed by the allocations and then
     827             :    a wksp detach (and faster still to use the advanced APIs to further
     828             :    amortize the fd_wksp_attach / fd_wksp_detach calls). */
     829             : 
     830             : char *
     831             : fd_wksp_cstr_alloc( char const * name,
     832             :                     ulong        align,
     833             :                     ulong        sz,
     834             :                     ulong        tag,
     835             :                     char *       cstr );
     836             : 
     837             : /* fd_wksp_cstr_free frees a wksp allocation specified by a cstr
     838             :    containing [name]:[gaddr].  Ignoring parsing and error trapping, this
     839             :    is a shorthand for:
     840             : 
     841             :       fd_wksp_t * wksp = fd_wksp_attach( name );
     842             :       fd_wksp_free( wksp, gaddr );
     843             :       fd_wksp_detach( wksp );
     844             : 
     845             :    As such, if doing many frees from the same wksp, it is faster to do a
     846             :    fd_wksp_attach upfront, followed by the frees and then a
     847             :    fd_wksp_detach (and faster still to use the advanced APIs to further
     848             :    amortize the fd_wksp_attach / fd_wksp_detach calls.) */
     849             : 
     850             : void
     851             : fd_wksp_cstr_free( char const * cstr );
     852             : 
     853             : /* fd_wksp_cstr_tag queries the tag of a wksp allocation specified by a
     854             :    cstr containing [name]:[gaddr].  Ignoring parsing and error trapping,
     855             :    this is a shorthand for:
     856             : 
     857             :       fd_wksp_t * wksp = fd_wksp_attach( name );
     858             :       ulong tag = fd_wksp_tag( wksp, gaddr );
     859             :       fd_wksp_detach( wksp );
     860             : 
     861             :    As such, if doing many queries on the same wksp, it is faster to do
     862             :    fd_wksp_attach upfront, followed by the queries and then a
     863             :    fd_wksp_detach (and faster still to use the advanced APIs to further
     864             :    amortize the fd_wksp_attach / fd_wksp_detach calls.) */
     865             : 
     866             : ulong
     867             : fd_wksp_cstr_tag( char const * cstr );
     868             : 
     869             : /* fd_wksp_cstr_memset memsets a wksp allocation specified by a cstr
     870             :    containing [name]:[gaddr] to c.  Ignoring parsing and error trapping,
     871             :    equivalent to:
     872             : 
     873             :       fd_wksp_t * wksp = fd_wksp_attach( name );
     874             :       fd_wksp_memset( wksp, gaddr, c );
     875             :       fd_wksp_detach( wksp );
     876             : 
     877             :    As such, if doing many memset in the same wksp, it is faster to do a
     878             :    fd_wksp_attach upfront, followed by the memsets and then a
     879             :    fd_wksp_detach (and faster still to use the advanced APIs to further
     880             :    amortize the fd_wksp_attach / fd_wksp_detach calls.) */
     881             : 
     882             : void
     883             : fd_wksp_cstr_memset( char const * cstr,
     884             :                      int          c );
     885             : 
     886             : /* fd_wksp_map returns a pointer in the caller's address space to
     887             :    the wksp allocation specified by a cstr containing [name]:[gaddr].
     888             :    [name] is the name of the shared memory region holding the wksp.
     889             :    [gaddr] is converted to a number via fd_cstr_to_ulong that should
     890             :    correspond to a valid non-NULL global address in that wksp.  Ignoring
     891             :    parsing, edge cases and error trapping, this is a shorthand for:
     892             : 
     893             :      fd_wksp_laddr( fd_wksp_attach( name ), gaddr )
     894             : 
     895             :    Returns non-NULL on successful (the lifetime of the returned pointer
     896             :    will be until fd_wksp_unmap is called on it).  Returns NULL and logs
     897             :    details on failure.
     898             : 
     899             :    fd_wksp_map is algorithmically efficient and reasonably low overhead
     900             :    (especially if is this not the first attachment to the wksp).
     901             : 
     902             :    TODO: consider const-correct variant? */
     903             : 
     904             : void *
     905             : fd_wksp_map( char const * cstr );
     906             : 
     907             : /* fd_wksp_unmap unmaps a pointer returned by fd_wksp_map, logs details
     908             :    if anything weird is detected.  Ignoring error trapping, this is a
     909             :    shorthand for:
     910             : 
     911             :      fd_wksp_detach( fd_wksp_containing( laddr ) )
     912             : 
     913             :    Undefined behavior if laddr is not currently mapped by fd_wksp_map.
     914             :    fd_wksp_unmap is not algorithmically efficient but practically still
     915             :    quite fast (especially if this is not the last attachment to wksp).
     916             :    This API can only be used on laddrs in wksp are either named or
     917             :    anonymous workspaces. */
     918             : 
     919             : void
     920             : fd_wksp_unmap( void const * laddr );
     921             : 
     922             : /* pod helper APIs ****************************************************/
     923             : 
     924             : /* Ignoring error trapping, fd_wksp_pod_attach( cstr ) is shorthand
     925             :    for:
     926             : 
     927             :      fd_pod_join( fd_wksp_map( cstr ) )
     928             : 
     929             :    Cannot fail from the caller's point of view (will terminate the
     930             :    thread group of the caller with a detailed FD_LOG_ERR message on
     931             :    failure.  Calls to fd_wksp_pod_attach should be paired with calls to
     932             :    fd_wksp_pod_detach when pod usage is done. */
     933             : 
     934             : uchar const *
     935             : fd_wksp_pod_attach( char const * cstr );
     936             : 
     937             : /* Ignoring error trapping, fd_wksp_pod_detach( pod ) is shorthand for:
     938             : 
     939             :      fd_wksp_unmap( fd_pod_leave( pod ) )
     940             : 
     941             :    Provided for symmetry with fd_wksp_pod_attach.  Cannot fail from the
     942             :    caller's point of view (will terminate the thread group of the caller
     943             :    with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
     944             :    if anything wonky occurs in the unmap under the hood). */
     945             : 
     946             : void
     947             : fd_wksp_pod_detach( uchar const * pod );
     948             : 
     949             : /* Ignoring error trapping, fd_wksp_pod_map( pod, path ) is shorthand
     950             :    for:
     951             : 
     952             :      fd_wksp_map( fd_pod_query_cstr( pod, path, NULL ) )
     953             : 
     954             :    Cannot fail from the caller's point of view (will terminate the
     955             :    thread group of the caller with detailed FD_LOG_ERR message on
     956             :    failure).  Calls to fd_wksp_pod_map should be paired with calls to
     957             :    fd_wksp_pod_unmap. */
     958             : 
     959             : void *
     960             : fd_wksp_pod_map( uchar const * pod,
     961             :                  char const *  path );
     962             : 
     963             : /* Ignoring error trapping, fd_wksp_pod_unmap( obj ) is shorthand for:
     964             : 
     965             :      fd_wksp_unmap( obj )
     966             : 
     967             :    Provided for symmetry with fd_wksp_pod_map.  Cannot fail from the
     968             :    caller's point of view (will terminate the thread group of the caller
     969             :    with a detailed FD_LOG_ERR message on failure and will FD_LOG_WARNING
     970             :    if anything wonky occurs in the unmap under the hood). */
     971             : 
     972             : void
     973             : fd_wksp_pod_unmap( void * obj );
     974             : 
     975             : /* io APIs ************************************************************/
     976             : 
     977             : /* fd_wksp_checkpt_tpool will write the wksp's state to a file using
     978             :    tpool threads [t0,t1).  Assumes the caller is thread t0 and threads
     979             :    (t0,t1) are available.  The file will be located at path with UNIX
     980             :    style permissions given by mode.  style specifies the checkpt style
     981             :    and should be a FD_WKSP_CHECKPT_STYLE_* value or 0 (0 indicates to
     982             :    use FD_WKSP_CHECKPT_STYLE_DEFAULT).  uinfo points to a cstr with
     983             :    optional additional user context (NULL will be treated as the empty
     984             :    string "" ... if the strlen is longer than 16384 bytes, the info will
     985             :    be truncated to a strlen of 16383).
     986             : 
     987             :    Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
     988             :    (logs details).  Reasons for failure include INVAL (NULL wksp, NULL
     989             :    path, bad mode, unsupported style), CORRUPT (wksp memory corruption
     990             :    detected), FAIL (fail already exists, I/O error).  On failure, this
     991             :    will make a best effort to clean up after any partially written
     992             :    checkpt file.
     993             : 
     994             :    fd_wksp_checkpt is a convenience wrapper for serial checkpts. */
     995             : 
     996             : int
     997             : fd_wksp_checkpt_tpool( fd_tpool_t * tpool,
     998             :                        ulong        t0,
     999             :                        ulong        t1,
    1000             :                        fd_wksp_t *  wksp,
    1001             :                        char const * path,
    1002             :                        ulong        mode,
    1003             :                        int          style,
    1004             :                        char const * uinfo );
    1005             : 
    1006             : static inline int
    1007             : fd_wksp_checkpt( fd_wksp_t *  wksp,
    1008             :                  char const * path,
    1009             :                  ulong        mode,
    1010             :                  int          style,
    1011          72 :                  char const * uinfo ) {
    1012          72 :   return fd_wksp_checkpt_tpool( NULL, 0UL, 1UL, wksp, path, mode, style, uinfo );
    1013          72 : }
    1014             : 
    1015             : /* fd_wksp_restore_tpool will replace all allocations in the current
    1016             :    workspace with the allocations from the checkpt at path.  The
    1017             :    restored workspace will use the given seed.  Tpool threads [t0,t1)
    1018             :    will be used for the restore.  Assumes the caller is thread t0 and
    1019             :    threads (t0,t1) are available.
    1020             : 
    1021             :    IMPORTANT!  It is okay for wksp to have a different size, backing
    1022             :    page sz and/or numa affinity than the original wksp.  The only
    1023             :    requirements are the wksp be able to support as many allocations as
    1024             :    are in the checkpt and that these partitions can be restored to their
    1025             :    original positions in wksp's global address space.  If wksp has
    1026             :    part_max in checkpt's [alloc_cnt,part_max] and a data_max>=checkpt's
    1027             :    data_max, this is guaranteed.  Likewise, the number and range of
    1028             :    threads used on restore does _not_ need to match the range used on
    1029             :    checkpt.
    1030             : 
    1031             :    Returns FD_WKSP_SUCCESS (0) on success or a FD_WKSP_ERR_* on failure
    1032             :    (logs details).  Reasons for failure include INVAL (NULL wksp, NULL
    1033             :    path), FAIL or CORRUPT (couldn't open checkpt, I/O error, checkpt
    1034             :    format error, incompatible wksp for checkpt, etc ... logs details).
    1035             :    For the INVAL and FAIL cases, the original workspace allocations was
    1036             :    untouched.  For the CORRUPT case, original workspace allocations were
    1037             :    removed because the checkpt issues were detected after the restore
    1038             :    process began (a best effort to reset wksp to the empty state was
    1039             :    done before return).
    1040             : 
    1041             :    fd_wksp_restore is a convenience wrapper for serial restores. */
    1042             : 
    1043             : int
    1044             : fd_wksp_restore_tpool( fd_tpool_t * tpool,
    1045             :                        ulong        t0,
    1046             :                        ulong        t1,
    1047             :                        fd_wksp_t *  wksp,
    1048             :                        char const * path,
    1049             :                        uint         seed );
    1050             : 
    1051             : static inline int
    1052             : fd_wksp_restore( fd_wksp_t *  wksp,
    1053             :                  char const * path,
    1054          84 :                  uint         seed ) {
    1055          84 :   return fd_wksp_restore_tpool( NULL, 0UL, 1UL, wksp, path, seed );
    1056          84 : }
    1057             : 
    1058             : /* fd_wksp_preview previews the wksp checkpt at path.  On success,
    1059             :    returns FD_WKSP_SUCCESS (0), path seems to contain a supported wksp
    1060             :    checkpt and, if opt_preview was non-NULL, *opt_preview will contain,
    1061             :    at a minimum, the info needed to create a new wksp with the same
    1062             :    parameters as the wksp at path.  On failure, returns a FD_WKSP_ERR
    1063             :    (negative, silent) and *_opt_preview is unchanged.  Returns for
    1064             :    failure include INVAL (NULL path), FAIL (unable to read checkpt
    1065             :    header at path), CORRUPT (the leading bytes at path don't appear to
    1066             :    be a wksp checkpt). */
    1067             : 
    1068             : struct fd_wksp_preview {
    1069             :   int   style;
    1070             :   uint  seed;
    1071             :   ulong part_max;
    1072             :   ulong data_max;
    1073             :   char  name[ FD_SHMEM_NAME_MAX ]; /* cstr holding the original wksp name */
    1074             : };
    1075             : 
    1076             : typedef struct fd_wksp_preview fd_wksp_preview_t;
    1077             : 
    1078             : int
    1079             : fd_wksp_preview( char const *        path,
    1080             :                  fd_wksp_preview_t * _opt_preview );
    1081             : 
    1082             : /* fd_wksp_printf pretty prints to fd (e.g. fileno(stdout)) information
    1083             :    about the wksp checkpt at path.  verbose specifies the verbosity
    1084             :    level.  Typical verbose levels are:
    1085             : 
    1086             :      <0 - do not print
    1087             :       0 - preview info
    1088             :       1 - verbose 0 + metadata
    1089             :       2 - verbose 1 + build and user info
    1090             :       3 - verbose 2 + partition summary info
    1091             :       4 - verbose 3 + individual allocated partition metdata
    1092             :      >4 - verbose 4 + hex dumps of allocated partition data
    1093             : 
    1094             :    but this can vary for different checkpt styles.  The return value has
    1095             :    the same interpretation as printf. */
    1096             : 
    1097             : int
    1098             : fd_wksp_printf( int          fd,
    1099             :                 char const * path,
    1100             :                 int          verbose );
    1101             : 
    1102             : /* fd_wksp_mprotect marks all the memory in a workspace as read-only
    1103             :    (flag==1) or read-write (flag==0). Accessing read-only memory produces
    1104             :    a seg fault. */
    1105             : 
    1106             : void
    1107             : fd_wksp_mprotect( fd_wksp_t * wksp, int flag );
    1108             : 
    1109             : FD_PROTOTYPES_END
    1110             : 
    1111             : #endif /* HEADER_fd_src_util_wksp_fd_wksp_h */

Generated by: LCOV version 1.14