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
|