LCOV - code coverage report
Current view: top level - util/shmem - fd_shmem_user.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 214 367 58.3 %
Date: 2025-09-17 04:38:03 Functions: 10 14 71.4 %

          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        2667 :                       char const *             name ) {
      25        2667 :   ulong len = fd_shmem_name_len( name );
      26        2667 :   if( FD_UNLIKELY( !len ) ) return NULL;
      27        2541 :   fd_memset( key->cstr, 0, FD_SHMEM_NAME_MAX );
      28        2541 :   fd_memcpy( key->cstr, name, len );
      29        2541 :   return key;
      30        2667 : }
      31             : 
      32             : static fd_shmem_private_key_t const fd_shmem_private_key_null; /* Will be zeros at thread group start */
      33             : 
      34      824169 : #define FD_SHMEM_PRIVATE_MAP_LG_SLOT_CNT (8)
      35      817689 : #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        4608 : #define MAP_T                 fd_shmem_join_info_t
      40        6480 : #define MAP_LG_SLOT_CNT       FD_SHMEM_PRIVATE_MAP_LG_SLOT_CNT
      41        6480 : #define MAP_KEY_T             fd_shmem_private_key_t
      42        1872 : #define MAP_KEY_NULL          fd_shmem_private_key_null
      43      823794 : #define MAP_KEY_INVAL(k)      (!((k).cstr[0]))
      44        1641 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp( (k0).cstr, (k1).cstr, FD_SHMEM_NAME_MAX ))
      45             : #define MAP_KEY_EQUAL_IS_SLOW (1)
      46        4608 : #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        2469 :                                     fd_shmem_join_info_t * def ) {
      60      271233 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ )
      61      271062 :     if( ((!fd_shmem_private_map_key_inval( map[slot_idx].key )) & (map[slot_idx].join==join)) ) return &map[slot_idx];
      62         171 :   return def;
      63        2469 : }
      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        3153 :                                     fd_shmem_join_info_t * def ) {
      70      546456 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
      71      546252 :     ulong j0 = (ulong)map[slot_idx].shmem;
      72      546252 :     ulong j1 = j0 + map[slot_idx].page_sz*map[slot_idx].page_cnt - 1UL;
      73      546252 :     if( ((!fd_shmem_private_map_key_inval( map[slot_idx].key )) & (a1>=j0) & (a0<=j1)) ) return &map[slot_idx];
      74      546252 :   }
      75         204 :   return def;
      76        3153 : }
      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 atleast partially mapped and we cannot grab it.
      86             :  */
      87             : static void *
      88             : fd_shmem_private_grab_region( ulong addr,
      89             :                               ulong size,
      90        1896 :                               int   prot ) {
      91        1896 :   void * mmap_ret = mmap( (void*)addr, size, prot, MAP_ANON|MAP_PRIVATE, -1, 0 );
      92        1896 :   if( FD_UNLIKELY( mmap_ret == MAP_FAILED ) ) return mmap_ret;
      93             : 
      94        1896 :   if( FD_UNLIKELY( (ulong)mmap_ret != addr ) ) {
      95           0 :     if( munmap( mmap_ret, size ) ) {
      96           0 :       FD_LOG_ERR(( "failed to unmap temporary mapping, munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      97           0 :     }
      98           0 :     return MAP_FAILED;
      99           0 :   }
     100             : 
     101        1896 :   return mmap_ret;
     102        1896 : }
     103             : 
     104             : void *
     105             : fd_shmem_private_map_rand( ulong size,
     106             :                            ulong align,
     107        1896 :                            int   prot ) {
     108        1896 :   ulong ret_addr = 0;
     109             : 
     110             :   /* Failure is unlikely, 1000 iterations should guarantee success */
     111        1896 :   for( ulong i = 0; i < 1000; i++ ) {
     112        1896 :     long n = getrandom( &ret_addr, sizeof(ret_addr), 0 );
     113        1896 :     if( FD_UNLIKELY( n!=sizeof(ret_addr) ) ) FD_LOG_ERR(( "could not generate random address, getrandom() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     114             : 
     115             :     /* Assume 47-bit virtual addressing */
     116        1896 :     ret_addr &= 0x00007FFFFFFFFFFFUL;
     117        1896 :     ret_addr  = fd_ulong_align_up( ret_addr, align );
     118             : 
     119        1896 :     if( fd_shmem_private_grab_region( ret_addr, size, prot )!=MAP_FAILED ) {
     120        1896 :       return (void *)ret_addr;
     121        1896 :     }
     122        1896 :   }
     123             : 
     124           0 :   FD_LOG_ERR(( "unable to find random address for memory map after 1000 attempts" ));
     125           0 : }
     126             : 
     127             : static fd_shmem_join_info_t fd_shmem_private_map[ FD_SHMEM_PRIVATE_MAP_SLOT_CNT ]; /* Empty on thread group start */
     128             : static ulong                fd_shmem_private_map_cnt;                              /* 0 on thread group start */
     129             : 
     130             : void *
     131             : fd_shmem_join( char const *               name,
     132             :                int                        mode,
     133             :                fd_shmem_joinleave_func_t  join_func,
     134             :                void *                     context,
     135             :                fd_shmem_join_info_t *     opt_info,
     136        2496 :                int                        lock_pages ) {
     137             : 
     138             :   /* Check input args */
     139             : 
     140        2496 :   fd_shmem_private_key_t key;
     141        2496 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) {
     142         126 :     FD_LOG_WARNING(( "bad name (%s)", name ? name : "NULL" ));
     143         126 :     return NULL;
     144         126 :   }
     145             : 
     146        2370 :   if( FD_UNLIKELY( !( (mode==FD_SHMEM_JOIN_MODE_READ_ONLY) | (mode==FD_SHMEM_JOIN_MODE_READ_WRITE) ) ) ) {
     147           0 :     FD_LOG_WARNING(( "unsupported join mode (%i) for %s", mode, name ));
     148           0 :     return NULL;
     149           0 :   }
     150             : 
     151        2370 :   FD_SHMEM_LOCK;
     152             : 
     153             :   /* Query for an existing mapping */
     154             : 
     155        2370 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     156        2370 :   if( join_info ) {
     157         426 :     if( FD_UNLIKELY( join_info->ref_cnt<0L ) ) {
     158           0 :       FD_LOG_WARNING(( "join/leave circular dependency detected for %s", name ));
     159           0 :       FD_SHMEM_UNLOCK;
     160           0 :       return NULL;
     161           0 :     }
     162         426 :     join_info->ref_cnt++;
     163             : 
     164         426 :     if( opt_info ) *opt_info = *join_info;
     165         426 :     FD_SHMEM_UNLOCK;
     166         426 :     return join_info->join;
     167         426 :   }
     168             : 
     169             :   /* Not currently mapped.  See if we have enough room.  */
     170             : 
     171        1944 :   if( FD_UNLIKELY( fd_shmem_private_map_cnt>=FD_SHMEM_JOIN_MAX ) ) {
     172           0 :     FD_SHMEM_UNLOCK;
     173           0 :     FD_LOG_WARNING(( "too many concurrent joins for %s", name ));
     174           0 :     return NULL;
     175           0 :   }
     176             : 
     177             :   /* We have enough room for it.  Try to map the memory. */
     178             : 
     179        1944 :   fd_shmem_info_t shmem_info[1];
     180        1944 :   if( FD_UNLIKELY( fd_shmem_info( name, 0UL, shmem_info ) ) ) {
     181          48 :     FD_SHMEM_UNLOCK;
     182          48 :     FD_LOG_WARNING(( "unable to query region \"%s\"\n\tprobably does not exist or bad permissions", name ));
     183          48 :     return NULL;
     184          48 :   }
     185        1896 :   ulong page_sz  = shmem_info->page_sz;
     186        1896 :   ulong page_cnt = shmem_info->page_cnt;
     187        1896 :   ulong sz       = page_sz*page_cnt;
     188        1896 :   int   rw       = (mode==FD_SHMEM_JOIN_MODE_READ_WRITE);
     189             : 
     190             :   /* Map the region into our address space. */
     191             : 
     192        1896 :   char path[ FD_SHMEM_PRIVATE_PATH_BUF_MAX ];
     193        1896 :   int fd = open( fd_shmem_private_path( name, page_sz, path ), rw ? O_RDWR : O_RDONLY, (mode_t)0 );
     194        1896 :   if( FD_UNLIKELY( fd==-1 ) ) {
     195           0 :     FD_SHMEM_UNLOCK;
     196           0 :     FD_LOG_WARNING(( "open(\"%s\",%s,0) failed (%i-%s)", path, rw ? "O_RDWR" : "O_RDONLY", errno, fd_io_strerror( errno ) ));
     197           0 :     return NULL;
     198           0 :   }
     199             : 
     200             :   /* Generate a random address that we are guaranteed to be able to map */
     201        1896 :   void * const map_addr = fd_shmem_private_map_rand( sz, page_sz, PROT_READ );
     202        1896 :   if( FD_UNLIKELY( map_addr==MAP_FAILED ) ) FD_LOG_ERR(( "fd_shmem_private_map_rand failed" ));
     203             : 
     204             :   /* Note that MAP_HUGETLB and MAP_HUGE_* are implied by the mount point */
     205        1896 :   void * shmem = mmap( map_addr, sz, PROT_READ|( rw?PROT_WRITE:0 ) , MAP_SHARED|MAP_FIXED, fd, (off_t)0 );
     206             : 
     207        1896 :   int mmap_errno = errno;
     208        1896 :   if( FD_UNLIKELY( close( fd ) ) )
     209           0 :     FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
     210             : 
     211             :   /* Validate the mapping */
     212             : 
     213        1896 :   if( FD_UNLIKELY( shmem==MAP_FAILED ) ) {
     214           0 :     FD_SHMEM_UNLOCK;
     215           0 :     FD_LOG_WARNING(( "mmap(%p,%lu KiB,%s,MAP_SHARED,\"%s\",0) failed (%i-%s)",
     216           0 :                      map_addr, sz>>10, rw ? "PROT_READ|PROT_WRITE" : "PROT_READ", path, mmap_errno, fd_io_strerror( mmap_errno ) ));
     217           0 :     return NULL;
     218           0 :   }
     219             : 
     220        1896 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, page_sz ) ) ) {
     221           0 :     if( FD_UNLIKELY( munmap( shmem, sz ) ) )
     222           0 :       FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     223           0 :                        path, sz>>10, errno, fd_io_strerror( errno ) ));
     224           0 :     FD_SHMEM_UNLOCK;
     225           0 :     FD_LOG_WARNING(( "misaligned memory mapping for \"%s\"\n\t"
     226           0 :                      "This thread group's hugetlbfs mount path (--shmem-path / FD_SHMEM_PATH):\n\t"
     227           0 :                      "\t%s\n\t"
     228           0 :                      "has probably been corrupted and needs to be redone.\n\t"
     229           0 :                      "See 'bin/fd_shmem_cfg help' for more information.",
     230           0 :                      path, fd_shmem_private_base ));
     231           0 :     return NULL;
     232           0 :   }
     233             : 
     234             : 
     235        1896 :   if( FD_LIKELY( lock_pages ) ) {
     236             :     /* Lock this region in DRAM to prevent it going to swap and (try) to
     237             :        keep the virtual to physical DRAM mapping fixed for the join
     238             :        duration. */
     239             : 
     240        1896 :     if( FD_UNLIKELY( fd_numa_mlock( shmem, sz ) ) )
     241           0 :       FD_LOG_WARNING(( "fd_numa_mlock(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     242        1896 :                       path, sz>>10, errno, fd_io_strerror( errno ) ));
     243        1896 :   }
     244             : 
     245             :   /* Advise the kernel to not dump this region to avoid
     246             :       large shared mappings in concurrent use by multiple processes
     247             :       destroying the system with core files if a bunch of thread using
     248             :       this mapping seg fault concurrently. */
     249        1896 :   if( FD_UNLIKELY( madvise( shmem, sz, MADV_DONTDUMP ) ) )
     250           0 :     FD_LOG_WARNING(( "madvise(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     251        1896 :                      path, sz>>10, errno, fd_io_strerror( errno ) ));
     252             : 
     253             :   /* We have mapped the region.  Try to complete the join.  Note:
     254             :      map_query above and map_insert could be combined to improve
     255             :      efficiency further here (and eliminate the paranoid if check in the
     256             :      process). */
     257             : 
     258        1896 :   join_info = fd_shmem_private_map_insert( fd_shmem_private_map, key );
     259        1896 :   if( FD_UNLIKELY( !join_info ) ) /* should be impossible */
     260           0 :     FD_LOG_ERR(( "unable to insert region \"%s\" (internal error)", name ));
     261        1896 :   fd_shmem_private_map_cnt++;
     262             : 
     263        1896 :   join_info->ref_cnt  = -1L;  /* Mark join/leave in progress so we can detect circular join/leave dependencies */
     264        1896 :   join_info->join     = NULL; /* Overridden below */
     265        1896 :   join_info->shmem    = shmem;
     266        1896 :   join_info->page_sz  = page_sz;
     267        1896 :   join_info->page_cnt = page_cnt;
     268        1896 :   join_info->mode     = mode;
     269             :   /* join_info->hash handled by insert */
     270             :   /* join_info->name "                 */
     271             :   /* join_info->key  "                 */
     272             : 
     273        1896 :   void * join = join_func ? join_func( context, join_info ): shmem; /* Reset by the join func if provided */
     274        1896 :   if( FD_UNLIKELY( !join ) ) {
     275           0 :     fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     276           0 :     fd_shmem_private_map_cnt--;
     277           0 :     if( FD_UNLIKELY( munmap( shmem, sz ) ) )
     278           0 :       FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     279           0 :                        name, sz>>10, errno, fd_io_strerror( errno ) ));
     280           0 :     FD_SHMEM_UNLOCK;
     281           0 :     FD_LOG_WARNING(( "unable to join region \"%s\"", name ));
     282           0 :     return NULL;
     283           0 :   }
     284        1896 :   join_info->ref_cnt = 1UL;
     285        1896 :   join_info->join    = join;
     286             : 
     287        1896 :   if( opt_info ) *opt_info = *join_info;
     288        1896 :   FD_SHMEM_UNLOCK;
     289        1896 :   return join;
     290        1896 : }
     291             : 
     292             : int
     293             : fd_shmem_leave( void *                    join,
     294             :                 fd_shmem_joinleave_func_t leave_func,
     295        2235 :                 void *                    context ) {
     296        2235 :   if( FD_UNLIKELY( !join ) ) { FD_LOG_WARNING(( "NULL join" )); return 1; }
     297             : 
     298        2235 :   FD_SHMEM_LOCK;
     299             : 
     300        2235 :   if( FD_UNLIKELY( !fd_shmem_private_map_cnt ) ) {
     301           3 :     FD_SHMEM_UNLOCK;
     302           3 :     FD_LOG_WARNING(( "join is not a current join" ));
     303           3 :     return 1;
     304           3 :   }
     305        2232 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     306        2232 :   if( FD_UNLIKELY( !join_info ) ) {
     307           0 :     FD_SHMEM_UNLOCK;
     308           0 :     FD_LOG_WARNING(( "join is not a current join" ));
     309           0 :     return 1;
     310           0 :   }
     311             : 
     312        2232 :   long ref_cnt = join_info->ref_cnt;
     313        2232 :   if( join_info->ref_cnt>1L ) {
     314         426 :     join_info->ref_cnt = ref_cnt-1L;
     315         426 :     FD_SHMEM_UNLOCK;
     316         426 :     return 0;
     317         426 :   }
     318             : 
     319        1806 :   if( join_info->ref_cnt==-1L ) {
     320           0 :     FD_SHMEM_UNLOCK;
     321           0 :     FD_LOG_WARNING(( "join/leave circular dependency detected for %s", join_info->name ));
     322           0 :     return 1;
     323           0 :   }
     324             : 
     325        1806 :   if( FD_UNLIKELY( join_info->ref_cnt!=1L ) ) /* Should be impossible */
     326           0 :     FD_LOG_WARNING(( "unexpected ref count for %s; attempting to continue", join_info->name ));
     327             : 
     328        1806 :   char const * name     = join_info->name;     /* Just in case leave_func clobbers */
     329        1806 :   void *       shmem    = join_info->shmem;    /* " */
     330        1806 :   ulong        page_sz  = join_info->page_sz;  /* " */
     331        1806 :   ulong        page_cnt = join_info->page_cnt; /* " */
     332             : 
     333        1806 :   if( leave_func ) {
     334        1746 :     join_info->ref_cnt = -1L; /* Mark join/leave is in progress so we can detect join/leave circular dependencies */
     335        1746 :     leave_func( context, join_info );
     336        1746 :   }
     337             : 
     338        1806 :   int error = 0;
     339        1806 :   ulong sz = page_sz*page_cnt;
     340        1806 :   if( FD_UNLIKELY( munmap( shmem, sz ) ) ) {
     341           0 :     FD_LOG_WARNING(( "munmap(\"%s\",%lu KiB) failed (%i-%s); attempting to continue",
     342           0 :                      name, sz>>10, errno, fd_io_strerror( errno ) ));
     343           0 :     error = 1;
     344           0 :   }
     345             : 
     346        1806 :   fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     347        1806 :   fd_shmem_private_map_cnt--;
     348        1806 :   FD_SHMEM_UNLOCK;
     349        1806 :   return error;
     350        1806 : }
     351             : 
     352             : int
     353             : fd_shmem_join_query_by_name( char const *           name,
     354           0 :                              fd_shmem_join_info_t * opt_info ) {
     355           0 :   fd_shmem_private_key_t key;
     356           0 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) return EINVAL;
     357             : 
     358           0 :   FD_SHMEM_LOCK;
     359             : 
     360           0 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     361           0 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     362           0 :   if( !join_info ) { FD_SHMEM_UNLOCK; return ENOENT; }
     363           0 :   if( opt_info ) *opt_info = *join_info;
     364             : 
     365           0 :   FD_SHMEM_UNLOCK;
     366           0 :   return 0;
     367           0 : }
     368             : 
     369             : int
     370             : fd_shmem_join_query_by_join( void const *           join,
     371           0 :                              fd_shmem_join_info_t * opt_info ) {
     372           0 :   if( FD_UNLIKELY( !join ) ) return EINVAL;
     373             : 
     374           0 :   FD_SHMEM_LOCK;
     375             : 
     376           0 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     377           0 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     378           0 :   if( FD_UNLIKELY( !join_info ) ) { FD_SHMEM_UNLOCK; return ENOENT; }
     379           0 :   if( opt_info ) *opt_info = *join_info;
     380             : 
     381           0 :   FD_SHMEM_UNLOCK;
     382           0 :   return 0;
     383           0 : }
     384             : 
     385             : int
     386             : fd_shmem_join_query_by_addr( void const *           addr,
     387             :                              ulong                  sz,
     388        2994 :                              fd_shmem_join_info_t * opt_info ) {
     389        2994 :   if( FD_UNLIKELY( !sz ) ) return ENOENT; /* empty range */
     390        2994 :   ulong a0 = (ulong)addr;
     391        2994 :   ulong a1 = a0+sz-1UL;
     392        2994 :   if( FD_UNLIKELY( a1<a0 ) ) return EINVAL; /* cyclic wrap range */
     393             : 
     394        2994 :   FD_SHMEM_LOCK;
     395             : 
     396        2994 :   if( !fd_shmem_private_map_cnt ) { FD_SHMEM_UNLOCK; return ENOENT; }
     397        2982 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_addr( fd_shmem_private_map, a0, a1, NULL );
     398        2982 :   if( FD_UNLIKELY( !join_info ) ) { FD_SHMEM_UNLOCK; return ENOENT; }
     399        2949 :   if( opt_info ) *opt_info = *join_info;
     400             : 
     401        2949 :   FD_SHMEM_UNLOCK;
     402        2949 :   return 0;
     403        2982 : }
     404             : 
     405             : int
     406             : fd_shmem_join_anonymous( char const * name,
     407             :                          int          mode,
     408             :                          void *       join,
     409             :                          void *       mem,
     410             :                          ulong        page_sz,
     411         171 :                          ulong        page_cnt ) {
     412             : 
     413             :   /* Check input args */
     414             : 
     415         171 :   fd_shmem_private_key_t key;
     416         171 :   if( FD_UNLIKELY( !fd_shmem_private_key( &key, name ) ) ) {
     417           0 :     FD_LOG_WARNING(( "bad name (%s)", name ? name : "NULL" ));
     418           0 :     return EINVAL;
     419           0 :   }
     420             : 
     421         171 :   if( FD_UNLIKELY( !( (mode==FD_SHMEM_JOIN_MODE_READ_ONLY) | (mode==FD_SHMEM_JOIN_MODE_READ_WRITE) ) ) ) {
     422           0 :     FD_LOG_WARNING(( "unsupported join mode (%i) for %s", mode, name ));
     423           0 :     return EINVAL;
     424           0 :   }
     425             : 
     426         171 :   if( FD_UNLIKELY( !join ) ) {
     427           0 :     FD_LOG_WARNING(( "NULL join" ));
     428           0 :     return EINVAL;
     429           0 :   }
     430             : 
     431         171 :   if( FD_UNLIKELY( !mem ) ) {
     432           0 :     FD_LOG_WARNING(( "NULL mem" ));
     433           0 :     return EINVAL;
     434           0 :   }
     435             : 
     436         171 :   if( FD_UNLIKELY( !fd_shmem_is_page_sz( page_sz ) ) ) {
     437           0 :     FD_LOG_WARNING(( "unsupported page_sz (%lu)", page_sz ));
     438           0 :     return EINVAL;
     439           0 :   }
     440             : 
     441         171 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, page_sz ) ) ) {
     442           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     443           0 :     return EINVAL;
     444           0 :   }
     445             : 
     446         171 :   if( FD_UNLIKELY( !page_cnt ) ) {
     447           0 :     FD_LOG_WARNING(( "unsupported page_sz (%lu)", page_sz ));
     448           0 :     return EINVAL;
     449           0 :   }
     450             : 
     451         171 :   if( FD_UNLIKELY( page_cnt > (ULONG_MAX/page_sz) ) ) {
     452           0 :     FD_LOG_WARNING(( "too large page cnt (%lu)", page_cnt ));
     453           0 :     return EINVAL;
     454           0 :   }
     455             : 
     456         171 :   ulong sz = page_cnt*page_sz;
     457         171 :   ulong a0 = (ulong)mem;
     458         171 :   ulong a1 = a0 + sz-1UL;
     459         171 :   if( FD_UNLIKELY( a1<a0 ) ) {
     460           0 :     FD_LOG_WARNING(( "bad mem range" ));
     461           0 :     return EINVAL;
     462           0 :   }
     463             : 
     464         171 :   FD_SHMEM_LOCK;
     465             : 
     466             :   /* Query for an existing mapping */
     467             : 
     468         171 :   fd_shmem_join_info_t * join_info;
     469             : 
     470         171 :   join_info = fd_shmem_private_map_query( fd_shmem_private_map, key, NULL );
     471         171 :   if( FD_UNLIKELY( join_info ) ) {
     472           0 :     FD_SHMEM_UNLOCK;
     473           0 :     FD_LOG_WARNING(( "%s already joined", name ));
     474           0 :     return EINVAL;
     475           0 :   }
     476             : 
     477         171 :   join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     478         171 :   if( FD_UNLIKELY( join_info ) ) {
     479           0 :     FD_SHMEM_UNLOCK;
     480           0 :     FD_LOG_WARNING(( "%s join handle already in use", name ));
     481           0 :     return EINVAL;
     482           0 :   }
     483             : 
     484         171 :   join_info = fd_shmem_private_map_query_by_addr( fd_shmem_private_map, a0, a1, NULL );
     485         171 :   if( FD_UNLIKELY( join_info ) ) {
     486           0 :     FD_SHMEM_UNLOCK;
     487           0 :     FD_LOG_WARNING(( "%s join memory already mapped", name ));
     488           0 :     return EINVAL;
     489           0 :   }
     490             : 
     491             :   /* Not currently mapped.  See if we have enough room.  */
     492             : 
     493         171 :   if( FD_UNLIKELY( fd_shmem_private_map_cnt>=FD_SHMEM_JOIN_MAX ) ) {
     494           0 :     FD_SHMEM_UNLOCK;
     495           0 :     FD_LOG_WARNING(( "too many concurrent joins for %s", name ));
     496           0 :     return EINVAL;
     497           0 :   }
     498             : 
     499             :   /* We have enough room for it.  Try to "map" the memory. */
     500             : 
     501         171 :   fd_shmem_info_t shmem_info[1];
     502         171 :   if( FD_UNLIKELY( !fd_shmem_info( name, 0UL, shmem_info ) ) )
     503           0 :     FD_LOG_WARNING(( "anonymous join to %s will shadow an existing shared memory region in this thread group; "
     504         171 :                      "attempting to continue", name ));
     505             : 
     506         171 :   join_info = fd_shmem_private_map_insert( fd_shmem_private_map, key );
     507         171 :   if( FD_UNLIKELY( !join_info ) ) /* should be impossible */
     508           0 :     FD_LOG_ERR(( "unable to insert region \"%s\" (internal error)", name ));
     509         171 :   fd_shmem_private_map_cnt++;
     510             : 
     511         171 :   join_info->ref_cnt  = 1L;
     512         171 :   join_info->join     = join;
     513         171 :   join_info->shmem    = mem;
     514         171 :   join_info->page_sz  = page_sz;
     515         171 :   join_info->page_cnt = page_cnt;
     516         171 :   join_info->mode     = mode;
     517             :   /* join_info->hash handled by insert */
     518             :   /* join_info->name "                 */
     519             :   /* join_info->key  "                 */
     520             : 
     521         171 :   FD_SHMEM_UNLOCK;
     522         171 :   return 0;
     523         171 : }
     524             : 
     525             : int
     526             : fd_shmem_leave_anonymous( void *                 join,
     527          72 :                           fd_shmem_join_info_t * opt_info ) {
     528             : 
     529          72 :   if( FD_UNLIKELY( !join ) ) {
     530           3 :     FD_LOG_WARNING(( "NULL join" ));
     531           3 :     return EINVAL;
     532           3 :   }
     533             : 
     534          69 :   FD_SHMEM_LOCK;
     535             : 
     536          69 :   if( FD_UNLIKELY( !fd_shmem_private_map_cnt ) ) {
     537           3 :     FD_SHMEM_UNLOCK;
     538           3 :     FD_LOG_WARNING(( "join is not a current join" ));
     539           3 :     return EINVAL;
     540           3 :   }
     541             : 
     542          66 :   fd_shmem_join_info_t * join_info = fd_shmem_private_map_query_by_join( fd_shmem_private_map, join, NULL );
     543          66 :   if( FD_UNLIKELY( !join_info ) ) {
     544           0 :     FD_SHMEM_UNLOCK;
     545           0 :     FD_LOG_WARNING(( "join is not a current join" ));
     546           0 :     return EINVAL;
     547           0 :   }
     548             : 
     549          66 :   if( FD_UNLIKELY( join_info->ref_cnt!=1L ) ) {
     550           0 :     FD_SHMEM_UNLOCK;
     551           0 :     FD_LOG_WARNING(( "join ref_cnt is not 1" ));
     552           0 :     return EINVAL;
     553           0 :   }
     554             : 
     555          66 :   if( opt_info ) {
     556          63 :     *opt_info = *join_info;
     557          63 :     opt_info->ref_cnt = 0L;
     558          63 :   }
     559             : 
     560          66 :   fd_shmem_private_map_remove( fd_shmem_private_map, join_info );
     561          66 :   fd_shmem_private_map_cnt--;
     562          66 :   FD_SHMEM_UNLOCK;
     563          66 :   return 0;
     564          66 : }
     565             : 
     566             : fd_shmem_join_info_t const *
     567           0 : fd_shmem_iter_begin( void ) {
     568           0 :   fd_shmem_join_info_t const * map = fd_shmem_private_map;
     569           0 :   for( ulong slot_idx=0UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
     570           0 :     if( !fd_shmem_private_map_key_inval( map[slot_idx].key ) ) return &map[slot_idx];
     571           0 :   }
     572           0 :   return NULL;
     573           0 : }
     574             : 
     575             : fd_shmem_join_info_t const *
     576           0 : fd_shmem_iter_next( fd_shmem_join_info_t const * iter ) {
     577           0 :   fd_shmem_join_info_t const * map = fd_shmem_private_map;
     578           0 :   for( ulong slot_idx=(ulong)(iter-map) + 1UL; slot_idx<FD_SHMEM_PRIVATE_MAP_SLOT_CNT; slot_idx++ ) {
     579           0 :     if( !fd_shmem_private_map_key_inval( map[slot_idx].key ) ) return &map[slot_idx];
     580           0 :   }
     581           0 :   return NULL;
     582           0 : }
     583             : 
     584             : #endif

Generated by: LCOV version 1.14