LCOV - code coverage report
Current view: top level - util/shmem - fd_shmem_user.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 235 399 58.9 %
Date: 2026-09-17 04:28:31 Functions: 11 14 78.6 %

          Line data    Source code
       1             : #if FD_HAS_HOSTED
       2             : #define _GNU_SOURCE
       3             : #endif
       4             : 
       5             : #include "fd_shmem_private.h"
       6             : 
       7             : #if FD_HAS_HOSTED
       8             : 
       9             : #include <errno.h>
      10             : #include <unistd.h>
      11             : #include <fcntl.h>
      12             : #include <sys/mman.h>
      13             : #include <sys/random.h>
      14             : 
      15             : /* fd_shmem_private_key converts the cstr pointed to by name into a
      16             :    valid key and stores it at the location pointed to by key assumed
      17             :    valid).  Returns key on success and NULL on failure (i.e. name does
      18             :    not point to a valid shmem region name).  All bytes of key will be
      19             :    unambiguously initialized so there is no issue with using things like
      20             :    memcmp to compare keys, etc. */
      21             : 
      22             : static inline fd_shmem_private_key_t *
      23             : fd_shmem_private_key( fd_shmem_private_key_t * key,
      24        2448 :                       char const *             name ) {
      25        2448 :   ulong len = fd_shmem_name_len( name );
      26        2448 :   if( FD_UNLIKELY( !len ) ) return NULL;
      27        2343 :   fd_memset( key->cstr, 0, FD_SHMEM_NAME_MAX );
      28        2343 :   fd_memcpy( key->cstr, name, len );
      29        2343 :   return key;
      30        2448 : }
      31             : 
      32             : static fd_shmem_private_key_t const fd_shmem_private_key_null; /* Will be zeros at thread group start */
      33             : 
      34     2187633 : #define FD_SHMEM_PRIVATE_MAP_LG_SLOT_CNT (8)
      35     2181759 : #define FD_SHMEM_PRIVATE_MAP_SLOT_CNT    (1UL<<FD_SHMEM_PRIVATE_MAP_LG_SLOT_CNT)
      36             : FD_STATIC_ASSERT( FD_SHMEM_JOIN_MAX < FD_SHMEM_PRIVATE_MAP_SLOT_CNT, increase_lg_slot_count );
      37             : 
      38             : #define MAP_NAME              fd_shmem_private_map
      39        4218 : #define MAP_T                 fd_shmem_join_info_t
      40        5874 : #define MAP_LG_SLOT_CNT       FD_SHMEM_PRIVATE_MAP_LG_SLOT_CNT
      41        5874 : #define MAP_KEY_T             fd_shmem_private_key_t
      42        1656 : #define MAP_KEY_NULL          fd_shmem_private_key_null
      43     2187156 : #define MAP_KEY_INVAL(k)      (!((k).cstr[0]))
      44        1452 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp( (k0).cstr, (k1).cstr, FD_SHMEM_NAME_MAX ))
      45             : #define MAP_KEY_EQUAL_IS_SLOW (1)
      46        4218 : #define MAP_KEY_HASH(k)       ((uint)fd_hash( 0UL, (k).cstr, FD_SHMEM_NAME_MAX ))
      47             : #include "../tmpl/fd_map.c"
      48             : 
      49             : /* fd_shmem_private_map_query_by_{join,addr} are some extra
      50             :    fd_shmem_private_map APIs allow looking up the join info for a region
      51             :    by its join handle and/or by a pointer at a byte in the region int
      52             :    the thread group's local address space.  These aren't algorithmically
      53             :    efficient but aren't expected to be and are plenty fast in normal use
      54             :    anyway. */
      55             : 
      56             : static inline fd_shmem_join_info_t *
      57             : fd_shmem_private_map_query_by_join( fd_shmem_join_info_t * map,
      58             :                                     void const *           join,
      59        2316 :                                     fd_shmem_join_info_t * def ) {
      60      289491 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ )
      61      289263 :     if( ((!fd_shmem_private_map_key_inval( map[slot_idx].key )) & (map[slot_idx].join==join)) ) return &map[slot_idx];
      62         228 :   return def;
      63        2316 : }
      64             : 
      65             : static inline fd_shmem_join_info_t *
      66             : fd_shmem_private_map_query_by_addr( fd_shmem_join_info_t * map,
      67             :                                     ulong                  a0,
      68             :                                     ulong                  a1,      /* Assumes a1>=a0 */
      69       16536 :                                     fd_shmem_join_info_t * def ) {
      70     1892268 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
      71     1892019 :     ulong j0 = (ulong)map[slot_idx].shmem;
      72     1892019 :     ulong j1 = j0 + map[slot_idx].page_sz*map[slot_idx].page_cnt - 1UL;
      73     1892019 :     if( ((!fd_shmem_private_map_key_inval( map[slot_idx].key )) & (a1>=j0) & (a0<=j1)) ) return &map[slot_idx];
      74     1892019 :   }
      75         249 :   return def;
      76       16536 : }
      77             : 
      78             : /*
      79             :  * fd_shmem_private_grab_region will attempt to map a region at the passed
      80             :  * address with the passed size. If the return value of `mmap` equals the
      81             :  * passed address this means the area of memory was unmapped previously and
      82             :  * we have successfully "grabbed" the region. We can then call `mmap` with
      83             :  * MAP_FIXED over the region and be certain no corruption occurs. If the
      84             :  * return value of `mmap` does not return the passed address this means that
      85             :  * the passed region is already at least partially mapped and we cannot grab it.
      86             :  *
      87             :  * Returns 0 on success, EEXIST if the region was already mapped (`mmap` does
      88             :  * not itself return EEXIST here, so there is no ambiguity), or a strerror
      89             :  * friendly error code otherwise.
      90             :  */
      91             : static int
      92             : fd_shmem_private_grab_region( ulong addr,
      93             :                               ulong size,
      94        1647 :                               int   prot ) {
      95        1647 :   void * mmap_ret = mmap( (void*)addr, size, prot, MAP_ANON|MAP_PRIVATE, -1, 0 );
      96        1647 :   if( FD_UNLIKELY( mmap_ret==MAP_FAILED ) ) return errno ? errno : EINVAL;
      97             : 
      98        1647 :   if( FD_UNLIKELY( (ulong)mmap_ret != addr ) ) {
      99           0 :     if( FD_UNLIKELY( munmap( mmap_ret, size ) ) ) {
     100           0 :       FD_LOG_ERR(( "failed to unmap temporary mapping, munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     101           0 :     }
     102           0 :     return EEXIST;
     103           0 :   }
     104             : 
     105        1647 :   return 0;
     106        1647 : }
     107             : 
     108             : /* Arbitrarily generous number of random addresses tried before returning
     109             :    ENOMEM and number of getrandom retries before returning EAGAIN. */
     110        1647 : #define FD_SHMEM_PRIVATE_MAP_RAND_MAX  (1000UL)
     111        1647 : #define FD_SHMEM_PRIVATE_GETRANDOM_MAX   (64UL)
     112             : 
     113             : int
     114             : fd_shmem_private_map_rand( ulong  size,
     115             :                            ulong  align,
     116             :                            int    mode,
     117        1647 :                            void * mem ) {
     118        1647 :   int   rw       = (mode==FD_SHMEM_JOIN_MODE_READ_WRITE);
     119        1647 :   int   prot     = PROT_READ | ( rw ? PROT_WRITE : 0 );
     120        1647 :   ulong ret_addr = 0UL;
     121             : 
     122             :   /* Failure is unlikely, FD_SHMEM_PRIVATE_MAP_RAND_MAX iterations should
     123             :      guarantee success */
     124        1647 :   for( ulong i=0UL; i<FD_SHMEM_PRIVATE_MAP_RAND_MAX; i++ ) {
     125        1647 :     long n = -1L;
     126        1647 :     for( ulong j=0UL; j<FD_SHMEM_PRIVATE_GETRANDOM_MAX; j++ ) {
     127        1647 :       n = getrandom( &ret_addr, sizeof(ret_addr), 0 );
     128        1647 :       if( FD_LIKELY( -1L!=n || errno!=EINTR ) ) break;
     129        1647 :     }
     130        1647 :     if( FD_UNLIKELY( n!=sizeof(ret_addr) ) ) {
     131           0 :       int err = ( errno==EINTR ) ? EAGAIN : ( errno ? errno : EINVAL );
     132           0 :       FD_LOG_WARNING(( "could not generate random address, getrandom() failed (%i-%s)", err, fd_io_strerror( err ) ));
     133           0 :       return err;
     134           0 :     }
     135             : 
     136             :     /* Assume 47-bit virtual addressing */
     137        1647 :     ret_addr &= 0x00007FFFFFFFFFFFUL;
     138        1647 :     ret_addr  = fd_ulong_align_up( ret_addr, align );
     139             : 
     140        1647 :     int err = fd_shmem_private_grab_region( ret_addr, size, prot );
     141        1647 :     if( FD_LIKELY( !err ) ) {
     142        1647 :       *(void **)mem = (void *)ret_addr;
     143        1647 :       return 0;
     144        1647 :     }
     145             : 
     146           0 :     if( FD_UNLIKELY( err!=EEXIST ) ) {
     147           0 :       FD_LOG_WARNING(( "unable to reserve a %lu byte region (align %lu, prot %i), mmap() failed (%i-%s)",
     148           0 :                        size, align, prot, err, fd_io_strerror( err ) ));
     149           0 :       return err;
     150           0 :     }
     151           0 :   }
     152             : 
     153           0 :   FD_LOG_WARNING(( "unable to find a free %lu byte region (align %lu, prot %i) after %lu random attempts, "
     154           0 :                    "the address space is likely too full or too fragmented",
     155           0 :                    size, align, prot, FD_SHMEM_PRIVATE_MAP_RAND_MAX ));
     156           0 :   return ENOMEM;
     157        1647 : }
     158             : 
     159             : static fd_shmem_join_info_t fd_shmem_private_map[ FD_SHMEM_PRIVATE_MAP_SLOT_CNT ]; /* Empty on thread group start */
     160             : static ulong                fd_shmem_private_map_cnt;                              /* 0 on thread group start */
     161             : 
     162             : void *
     163             : fd_shmem_join( char const *               name,
     164             :                int                        mode,
     165             :                int                        dump,
     166             :                fd_shmem_joinleave_func_t  join_func,
     167             :                void *                     context,
     168        2220 :                fd_shmem_join_info_t *     opt_info ) {
     169             : 
     170             :   /* Check input args */
     171             : 
     172        2220 :   fd_shmem_private_key_t key;
     173        2220 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) {
     174         105 :     FD_LOG_WARNING(( "bad name (%s)", name ? name : "NULL" ));
     175         105 :     return NULL;
     176         105 :   }
     177             : 
     178        2115 :   if( FD_UNLIKELY( !( (mode==FD_SHMEM_JOIN_MODE_READ_ONLY) | (mode==FD_SHMEM_JOIN_MODE_READ_WRITE) ) ) ) {
     179           0 :     FD_LOG_WARNING(( "unsupported join mode (%i) for %s", mode, name ));
     180           0 :     return NULL;
     181           0 :   }
     182             : 
     183        2115 :   FD_SHMEM_LOCK;
     184             : 
     185             :   /* Query for an existing mapping */
     186             : 
     187        2115 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     188        2115 :   if( join_info ) {
     189         426 :     if( FD_UNLIKELY( join_info->ref_cnt<0L ) ) {
     190           0 :       FD_LOG_WARNING(( "join/leave circular dependency detected for %s", name ));
     191           0 :       FD_SHMEM_UNLOCK;
     192           0 :       return NULL;
     193           0 :     }
     194         426 :     join_info->ref_cnt++;
     195             : 
     196         426 :     if( opt_info ) *opt_info = *join_info;
     197         426 :     FD_SHMEM_UNLOCK;
     198         426 :     return join_info->join;
     199         426 :   }
     200             : 
     201             :   /* Not currently mapped.  See if we have enough room.  */
     202             : 
     203        1689 :   if( FD_UNLIKELY( fd_shmem_private_map_cnt>=FD_SHMEM_JOIN_MAX ) ) {
     204           0 :     FD_SHMEM_UNLOCK;
     205           0 :     FD_LOG_WARNING(( "too many concurrent joins for %s", name ));
     206           0 :     return NULL;
     207           0 :   }
     208             : 
     209             :   /* We have enough room for it.  Try to map the memory. */
     210             : 
     211        1689 :   fd_shmem_info_t shmem_info[1];
     212        1689 :   if( FD_UNLIKELY( fd_shmem_info( name, 0UL, shmem_info ) ) ) {
     213          42 :     FD_SHMEM_UNLOCK;
     214          42 :     FD_LOG_WARNING(( "unable to query region \"%s\"\n\tprobably does not exist or bad permissions", name ));
     215          42 :     return NULL;
     216          42 :   }
     217        1647 :   ulong page_sz  = shmem_info->page_sz;
     218        1647 :   ulong page_cnt = shmem_info->page_cnt;
     219        1647 :   ulong sz       = page_sz*page_cnt;
     220        1647 :   int   rw       = (mode==FD_SHMEM_JOIN_MODE_READ_WRITE);
     221             : 
     222             :   /* Map the region into our address space. */
     223             : 
     224        1647 :   char path[ FD_SHMEM_PRIVATE_PATH_BUF_MAX ];
     225        1647 :   int fd = open( fd_shmem_private_path( name, page_sz, path ), rw ? O_RDWR : O_RDONLY, (mode_t)0 );
     226        1647 :   if( FD_UNLIKELY( fd==-1 ) ) {
     227           0 :     FD_SHMEM_UNLOCK;
     228           0 :     FD_LOG_WARNING(( "open(\"%s\",%s,0) failed (%i-%s)", path, rw ? "O_RDWR" : "O_RDONLY", errno, fd_io_strerror( errno ) ));
     229           0 :     return NULL;
     230           0 :   }
     231             : 
     232             :   /* Generate a random address that we are guaranteed to be able to map */
     233        1647 :   void * map_addr;
     234        1647 :   int    map_err = fd_shmem_private_map_rand( sz, page_sz, FD_SHMEM_JOIN_MODE_READ_ONLY, &map_addr );
     235        1647 :   if( FD_UNLIKELY( map_err ) ) {
     236           0 :     if( FD_UNLIKELY( close( fd ) ) ) {
     237           0 :       FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
     238           0 :     }
     239           0 :     FD_SHMEM_UNLOCK;
     240           0 :     FD_LOG_WARNING(( "unable to reserve a random address to map region \"%s\" (%lu KiB) (%i-%s)",
     241           0 :                      name, sz>>10, map_err, fd_io_strerror( map_err ) ));
     242           0 :     return NULL;
     243           0 :   }
     244             : 
     245             :   /* Note that MAP_HUGETLB and MAP_HUGE_* are implied by the mount point */
     246        1647 :   void * shmem = mmap( map_addr, sz, PROT_READ|( rw?PROT_WRITE:0 ) , MAP_SHARED|MAP_FIXED, fd, (off_t)0 );
     247             : 
     248        1647 :   int mmap_errno = errno;
     249        1647 :   if( FD_UNLIKELY( close( fd ) ) ) {
     250           0 :     FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
     251           0 :   }
     252             : 
     253             :   /* Validate the mapping */
     254             : 
     255        1647 :   if( FD_UNLIKELY( shmem==MAP_FAILED ) ) {
     256           0 :     FD_SHMEM_UNLOCK;
     257           0 :     FD_LOG_WARNING(( "mmap(%p,%lu KiB,%s,MAP_SHARED,\"%s\",0) failed (%i-%s)",
     258           0 :                      map_addr, sz>>10, rw ? "PROT_READ|PROT_WRITE" : "PROT_READ", path, mmap_errno, fd_io_strerror( mmap_errno ) ));
     259           0 :     return NULL;
     260           0 :   }
     261             : 
     262        1647 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, page_sz ) ) ) {
     263           0 :     if( FD_UNLIKELY( munmap( shmem, sz ) ) )
     264           0 :       FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     265           0 :                        path, sz>>10, errno, fd_io_strerror( errno ) ));
     266           0 :     FD_SHMEM_UNLOCK;
     267           0 :     FD_LOG_WARNING(( "misaligned memory mapping for \"%s\"\n\t"
     268           0 :                      "This thread group's hugetlbfs mount path (--shmem-path / FD_SHMEM_PATH):\n\t"
     269           0 :                      "\t%s\n\t"
     270           0 :                      "has probably been corrupted and needs to be redone.\n\t"
     271           0 :                      "See 'bin/fd_shmem_cfg help' for more information.",
     272           0 :                      path, fd_shmem_private_base ));
     273           0 :     return NULL;
     274           0 :   }
     275             : 
     276             :   /* Lock this region in DRAM to prevent it going to swap and (try) to
     277             :      keep the virtual to physical DRAM mapping fixed for the join
     278             :      duration.  Also advise the kernel to not dump this region to avoid
     279             :      large shared mappings in concurrent use by multiple processes
     280             :      destroying the system with core files if a bunch of thread using
     281             :      this mapping seg fault concurrently. */
     282             : 
     283        1647 :   if( FD_UNLIKELY( fd_numa_mlock( shmem, sz ) ) )
     284           0 :     FD_LOG_WARNING(( "fd_numa_mlock(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     285        1647 :                     path, sz>>10, errno, fd_io_strerror( errno ) ));
     286             : 
     287        1647 :   if( FD_LIKELY( !dump ) ) {
     288        1647 :     if( FD_UNLIKELY( madvise( shmem, sz, MADV_DONTDUMP ) ) )
     289           0 :       FD_LOG_WARNING(( "madvise(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     290        1647 :                       path, sz>>10, errno, fd_io_strerror( errno ) ));
     291        1647 :   }
     292             : 
     293             :   /* We have mapped the region.  Try to complete the join.  Note:
     294             :      map_query above and map_insert could be combined to improve
     295             :      efficiency further here (and eliminate the paranoid if check in the
     296             :      process). */
     297             : 
     298        1647 :   join_info = fd_shmem_private_map_insert( fd_shmem_private_map, key );
     299        1647 :   if( FD_UNLIKELY( !join_info ) ) /* should be impossible */
     300           0 :     FD_LOG_ERR(( "unable to insert region \"%s\" (internal error)", name ));
     301        1647 :   fd_shmem_private_map_cnt++;
     302             : 
     303        1647 :   join_info->ref_cnt  = -1L;  /* Mark join/leave in progress so we can detect circular join/leave dependencies */
     304        1647 :   join_info->join     = NULL; /* Overridden below */
     305        1647 :   join_info->shmem    = shmem;
     306        1647 :   join_info->page_sz  = page_sz;
     307        1647 :   join_info->page_cnt = page_cnt;
     308        1647 :   join_info->mode     = mode;
     309             :   /* join_info->hash handled by insert */
     310             :   /* join_info->name "                 */
     311             :   /* join_info->key  "                 */
     312             : 
     313        1647 :   void * join = join_func ? join_func( context, join_info ): shmem; /* Reset by the join func if provided */
     314        1647 :   if( FD_UNLIKELY( !join ) ) {
     315           0 :     fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     316           0 :     fd_shmem_private_map_cnt--;
     317           0 :     if( FD_UNLIKELY( munmap( shmem, sz ) ) )
     318           0 :       FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     319           0 :                        name, sz>>10, errno, fd_io_strerror( errno ) ));
     320           0 :     FD_SHMEM_UNLOCK;
     321           0 :     FD_LOG_WARNING(( "unable to join region \"%s\"", name ));
     322           0 :     return NULL;
     323           0 :   }
     324        1647 :   join_info->ref_cnt = 1UL;
     325        1647 :   join_info->join    = join;
     326             : 
     327        1647 :   if( opt_info ) *opt_info = *join_info;
     328        1647 :   FD_SHMEM_UNLOCK;
     329        1647 :   return join;
     330        1647 : }
     331             : 
     332             : int
     333             : fd_shmem_leave( void *                    join,
     334             :                 fd_shmem_joinleave_func_t leave_func,
     335        1995 :                 void *                    context ) {
     336        1995 :   if( FD_UNLIKELY( !join ) ) { FD_LOG_WARNING(( "NULL join" )); return 1; }
     337             : 
     338        1995 :   FD_SHMEM_LOCK;
     339             : 
     340        1995 :   if( FD_UNLIKELY( !fd_shmem_private_map_cnt ) ) {
     341           3 :     FD_SHMEM_UNLOCK;
     342           3 :     FD_LOG_WARNING(( "join is not a current join" ));
     343           3 :     return 1;
     344           3 :   }
     345        1992 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     346        1992 :   if( FD_UNLIKELY( !join_info ) ) {
     347           0 :     FD_SHMEM_UNLOCK;
     348           0 :     FD_LOG_WARNING(( "join is not a current join" ));
     349           0 :     return 1;
     350           0 :   }
     351             : 
     352        1992 :   long ref_cnt = join_info->ref_cnt;
     353        1992 :   if( join_info->ref_cnt>1L ) {
     354         426 :     join_info->ref_cnt = ref_cnt-1L;
     355         426 :     FD_SHMEM_UNLOCK;
     356         426 :     return 0;
     357         426 :   }
     358             : 
     359        1566 :   if( join_info->ref_cnt==-1L ) {
     360           0 :     FD_SHMEM_UNLOCK;
     361           0 :     FD_LOG_WARNING(( "join/leave circular dependency detected for %s", join_info->name ));
     362           0 :     return 1;
     363           0 :   }
     364             : 
     365        1566 :   if( FD_UNLIKELY( join_info->ref_cnt!=1L ) ) /* Should be impossible */
     366           0 :     FD_LOG_WARNING(( "unexpected ref count for %s; attempting to continue", join_info->name ));
     367             : 
     368        1566 :   char const * name     = join_info->name;     /* Just in case leave_func clobbers */
     369        1566 :   void *       shmem    = join_info->shmem;    /* " */
     370        1566 :   ulong        page_sz  = join_info->page_sz;  /* " */
     371        1566 :   ulong        page_cnt = join_info->page_cnt; /* " */
     372             : 
     373        1566 :   if( leave_func ) {
     374        1512 :     join_info->ref_cnt = -1L; /* Mark join/leave is in progress so we can detect join/leave circular dependencies */
     375        1512 :     leave_func( context, join_info );
     376        1512 :   }
     377             : 
     378        1566 :   int error = 0;
     379        1566 :   ulong sz = page_sz*page_cnt;
     380        1566 :   if( FD_UNLIKELY( munmap( shmem, sz ) ) ) {
     381           0 :     FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     382           0 :                      name, sz>>10, errno, fd_io_strerror( errno ) ));
     383           0 :     error = 1;
     384           0 :   }
     385             : 
     386        1566 :   fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     387        1566 :   fd_shmem_private_map_cnt--;
     388        1566 :   FD_SHMEM_UNLOCK;
     389        1566 :   return error;
     390        1566 : }
     391             : 
     392             : int
     393             : fd_shmem_join_query_by_name( char const *           name,
     394           0 :                              fd_shmem_join_info_t * opt_info ) {
     395           0 :   fd_shmem_private_key_t key;
     396           0 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) return EINVAL;
     397             : 
     398           0 :   FD_SHMEM_LOCK;
     399             : 
     400           0 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     401           0 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     402           0 :   if( !join_info ) { FD_SHMEM_UNLOCK; return ENOENT; }
     403           0 :   if( opt_info ) *opt_info = *join_info;
     404             : 
     405           0 :   FD_SHMEM_UNLOCK;
     406           0 :   return 0;
     407           0 : }
     408             : 
     409             : int
     410             : fd_shmem_join_query_by_join( void const *           join,
     411           6 :                              fd_shmem_join_info_t * opt_info ) {
     412           6 :   if( FD_UNLIKELY( !join ) ) return EINVAL;
     413             : 
     414           6 :   FD_SHMEM_LOCK;
     415             : 
     416           6 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     417           6 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     418           6 :   if( FD_UNLIKELY( !join_info ) ) { FD_SHMEM_UNLOCK; return ENOENT; }
     419           6 :   if( opt_info ) *opt_info = *join_info;
     420             : 
     421           6 :   FD_SHMEM_UNLOCK;
     422           6 :   return 0;
     423           6 : }
     424             : 
     425             : int
     426             : fd_shmem_join_query_by_addr( void const *           addr,
     427             :                              ulong                  sz,
     428       16320 :                              fd_shmem_join_info_t * opt_info ) {
     429       16320 :   if( FD_UNLIKELY( !sz ) ) return ENOENT; /* empty range */
     430       16320 :   ulong a0 = (ulong)addr;
     431       16320 :   ulong a1 = a0+sz-1UL;
     432       16320 :   if( FD_UNLIKELY( a1<a0 ) ) return EINVAL; /* cyclic wrap range */
     433             : 
     434       16320 :   FD_SHMEM_LOCK;
     435             : 
     436       16320 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     437       16308 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_addr( fd_shmem_private_map, a0, a1, NULL );
     438       16308 :   if( FD_UNLIKELY( !join_info ) ) { FD_SHMEM_UNLOCK; return ENOENT; }
     439       16287 :   if( opt_info ) *opt_info = *join_info;
     440             : 
     441       16287 :   FD_SHMEM_UNLOCK;
     442       16287 :   return 0;
     443       16308 : }
     444             : 
     445             : int
     446             : fd_shmem_join_anonymous( char const * name,
     447             :                          int          mode,
     448             :                          void *       join,
     449             :                          void *       mem,
     450             :                          ulong        page_sz,
     451         228 :                          ulong        page_cnt ) {
     452             : 
     453             :   /* Check input args */
     454             : 
     455         228 :   fd_shmem_private_key_t key;
     456         228 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) {
     457           0 :     FD_LOG_WARNING(( "bad name (%s)", name ? name : "NULL" ));
     458           0 :     return EINVAL;
     459           0 :   }
     460             : 
     461         228 :   if( FD_UNLIKELY( !( (mode==FD_SHMEM_JOIN_MODE_READ_ONLY) | (mode==FD_SHMEM_JOIN_MODE_READ_WRITE) ) ) ) {
     462           0 :     FD_LOG_WARNING(( "unsupported join mode (%i) for %s", mode, name ));
     463           0 :     return EINVAL;
     464           0 :   }
     465             : 
     466         228 :   if( FD_UNLIKELY( !join ) ) {
     467           0 :     FD_LOG_WARNING(( "NULL join" ));
     468           0 :     return EINVAL;
     469           0 :   }
     470             : 
     471         228 :   if( FD_UNLIKELY( !mem ) ) {
     472           0 :     FD_LOG_WARNING(( "NULL mem" ));
     473           0 :     return EINVAL;
     474           0 :   }
     475             : 
     476         228 :   if( FD_UNLIKELY( !fd_shmem_is_page_sz( page_sz ) ) ) {
     477           0 :     FD_LOG_WARNING(( "unsupported page_sz (%lu)", page_sz ));
     478           0 :     return EINVAL;
     479           0 :   }
     480             : 
     481         228 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, page_sz ) ) ) {
     482           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     483           0 :     return EINVAL;
     484           0 :   }
     485             : 
     486         228 :   if( FD_UNLIKELY( !page_cnt ) ) {
     487           0 :     FD_LOG_WARNING(( "unsupported page_sz (%lu)", page_sz ));
     488           0 :     return EINVAL;
     489           0 :   }
     490             : 
     491         228 :   if( FD_UNLIKELY( page_cnt > (ULONG_MAX/page_sz) ) ) {
     492           0 :     FD_LOG_WARNING(( "too large page cnt (%lu)", page_cnt ));
     493           0 :     return EINVAL;
     494           0 :   }
     495             : 
     496         228 :   ulong sz = page_cnt*page_sz;
     497         228 :   ulong a0 = (ulong)mem;
     498         228 :   ulong a1 = a0 + sz-1UL;
     499         228 :   if( FD_UNLIKELY( a1<a0 ) ) {
     500           0 :     FD_LOG_WARNING(( "bad mem range" ));
     501           0 :     return EINVAL;
     502           0 :   }
     503             : 
     504         228 :   FD_SHMEM_LOCK;
     505             : 
     506             :   /* Query for an existing mapping */
     507             : 
     508         228 :   fd_shmem_join_info_t * join_info;
     509             : 
     510         228 :   join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     511         228 :   if( FD_UNLIKELY( join_info ) ) {
     512           0 :     FD_SHMEM_UNLOCK;
     513           0 :     FD_LOG_WARNING(( "%s already joined", name ));
     514           0 :     return EINVAL;
     515           0 :   }
     516             : 
     517         228 :   join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     518         228 :   if( FD_UNLIKELY( join_info ) ) {
     519           0 :     FD_SHMEM_UNLOCK;
     520           0 :     FD_LOG_WARNING(( "%s join handle already in use", name ));
     521           0 :     return EINVAL;
     522           0 :   }
     523             : 
     524         228 :   join_info = fd_shmem_private_map_query_by_addr( fd_shmem_private_map, a0, a1, NULL );
     525         228 :   if( FD_UNLIKELY( join_info ) ) {
     526           0 :     FD_SHMEM_UNLOCK;
     527           0 :     FD_LOG_WARNING(( "%s join memory already mapped", name ));
     528           0 :     return EINVAL;
     529           0 :   }
     530             : 
     531             :   /* Not currently mapped.  See if we have enough room.  */
     532             : 
     533         228 :   if( FD_UNLIKELY( fd_shmem_private_map_cnt>=FD_SHMEM_JOIN_MAX ) ) {
     534           0 :     FD_SHMEM_UNLOCK;
     535           0 :     FD_LOG_WARNING(( "too many concurrent joins for %s", name ));
     536           0 :     return EINVAL;
     537           0 :   }
     538             : 
     539             :   /* We have enough room for it.  Try to "map" the memory. */
     540             : 
     541         228 :   fd_shmem_info_t shmem_info[1];
     542         228 :   if( FD_UNLIKELY( !fd_shmem_info( name, 0UL, shmem_info ) ) )
     543           0 :     FD_LOG_WARNING(( "anonymous join to %s will shadow an existing shared memory region in this thread group; "
     544         228 :                      "attempting to continue", name ));
     545             : 
     546         228 :   join_info = fd_shmem_private_map_insert( fd_shmem_private_map, key );
     547         228 :   if( FD_UNLIKELY( !join_info ) ) /* should be impossible */
     548           0 :     FD_LOG_ERR(( "unable to insert region \"%s\" (internal error)", name ));
     549         228 :   fd_shmem_private_map_cnt++;
     550             : 
     551         228 :   join_info->ref_cnt  = 1L;
     552         228 :   join_info->join     = join;
     553         228 :   join_info->shmem    = mem;
     554         228 :   join_info->page_sz  = page_sz;
     555         228 :   join_info->page_cnt = page_cnt;
     556         228 :   join_info->mode     = mode;
     557             :   /* join_info->hash handled by insert */
     558             :   /* join_info->name "                 */
     559             :   /* join_info->key  "                 */
     560             : 
     561         228 :   FD_SHMEM_UNLOCK;
     562         228 :   return 0;
     563         228 : }
     564             : 
     565             : int
     566             : fd_shmem_leave_anonymous( void *                 join,
     567          96 :                           fd_shmem_join_info_t * opt_info ) {
     568             : 
     569          96 :   if( FD_UNLIKELY( !join ) ) {
     570           3 :     FD_LOG_WARNING(( "NULL join" ));
     571           3 :     return EINVAL;
     572           3 :   }
     573             : 
     574          93 :   FD_SHMEM_LOCK;
     575             : 
     576          93 :   if( FD_UNLIKELY( !fd_shmem_private_map_cnt ) ) {
     577           3 :     FD_SHMEM_UNLOCK;
     578           3 :     FD_LOG_WARNING(( "join is not a current join" ));
     579           3 :     return EINVAL;
     580           3 :   }
     581             : 
     582          90 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     583          90 :   if( FD_UNLIKELY( !join_info ) ) {
     584           0 :     FD_SHMEM_UNLOCK;
     585           0 :     FD_LOG_WARNING(( "join is not a current join" ));
     586           0 :     return EINVAL;
     587           0 :   }
     588             : 
     589          90 :   if( FD_UNLIKELY( join_info->ref_cnt!=1L ) ) {
     590           0 :     FD_SHMEM_UNLOCK;
     591           0 :     FD_LOG_WARNING(( "join ref_cnt is not 1" ));
     592           0 :     return EINVAL;
     593           0 :   }
     594             : 
     595          90 :   if( opt_info ) {
     596          75 :     *opt_info = *join_info;
     597          75 :     opt_info->ref_cnt = 0L;
     598          75 :   }
     599             : 
     600          90 :   fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     601          90 :   fd_shmem_private_map_cnt--;
     602          90 :   FD_SHMEM_UNLOCK;
     603          90 :   return 0;
     604          90 : }
     605             : 
     606             : fd_shmem_join_info_t const *
     607           0 : fd_shmem_iter_begin( void ) {
     608           0 :   fd_shmem_join_info_t const * map = fd_shmem_private_map;
     609           0 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
     610           0 :     if( !fd_shmem_private_map_key_inval( map[slot_idx].key ) ) return &map[slot_idx];
     611           0 :   }
     612           0 :   return NULL;
     613           0 : }
     614             : 
     615             : fd_shmem_join_info_t const *
     616           0 : fd_shmem_iter_next( fd_shmem_join_info_t const * iter ) {
     617           0 :   fd_shmem_join_info_t const * map = fd_shmem_private_map;
     618           0 :   for( ulong slot_idx=(ulong)(iter-map) + 1UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
     619           0 :     if( !fd_shmem_private_map_key_inval( map[slot_idx].key ) ) return &map[slot_idx];
     620           0 :   }
     621           0 :   return NULL;
     622           0 : }
     623             : 
     624             : #endif

Generated by: LCOV version 1.14