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-01-08 12:08:44 Functions: 79 4550 1.7 %

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

Generated by: LCOV version 1.14