Line data Source code
1 : /* Declare API for object pools of bounded run-time maximum size
2 : suitable for non-concurrent high performance persistent IPC usage.
3 : Typical usage:
4 :
5 : struct myele {
6 : ulong next; // Technically POOL_IDX_T POOL_NEXT, can go anywhere in struct,
7 : // can be repurposed while acquired
8 : // will be clobbered while in pool though
9 : ... user data ...
10 : ... structures with power-of-2 sizes have particularly good HPC
11 : ... Feng Shui
12 : }
13 :
14 : typedef struct myele myele_t;
15 :
16 : #define POOL_NAME mypool
17 : #define POOL_T myele_t
18 : #include "tmpl/fd_pool.c"
19 :
20 : This will declare the following static inline APIs as a header only
21 : style library in the compilation unit:
22 :
23 : // align/footprint - Return the alignment/footprint required for a
24 : // memory region to be used as mypool that can hold up to max
25 : // elements. footprint returns 0 if max is invalid (e.g. so large
26 : // that footprint would overflow ULONG_MAX or zero if mypool is
27 : // supposed to have a sentinel).
28 : //
29 : // new - Format a memory region pointed to by shmem into a mypool.
30 : // Assumes shmem points to a region with the required alignment and
31 : // footprint not in use by anything else. Caller is not joined on
32 : // return. Returns shmem on success or NULL on failure (e.g. shmem
33 : // or max are obviously bad).
34 : //
35 : // join - Join a mypool. Assumes shpool points at a memory region
36 : // formatted as a mypool. Returns a pointer in the caller's
37 : // address space to a memory region indexed [0,max) on success and
38 : // NULL on failure (e.g. shmem is obviously bad). THIS IS NOT JUST
39 : // A SIMPLE CAST OF SHPOOL.
40 : //
41 : // leave - Leave a mypool. Assumes join points to a current local
42 : // join. Returns a pointer to the shared memory region the join on
43 : // success and NULL on failure. THIS IS NOT JUST A SIMPLE CAST OF
44 : // JOIN.
45 : //
46 : // delete - Unformat a memory region used as mypool. Assumes
47 : // shpool points to a formatted region with no current / future
48 : // joins. Returns a pointer to the unformatted memory region.
49 :
50 : ulong mypool_align ( void );
51 : ulong mypool_footprint( ulong max );
52 : void * mypool_new ( void * shmem, ulong max );
53 : myele_t * mypool_join ( void * shpool );
54 : void * mypool_leave ( myele_t * join );
55 : void * mypool_delete ( void * shpool );
56 :
57 : // Special values
58 :
59 : // All these assume join is a current local join to a mypool. The
60 : // sentinel APIs are only created if POOL_SENTINEL is requested.
61 :
62 : ulong mypool_idx_null ( myele_t const * join ); // Index of the null element (not accessible)
63 : // infinite lifetime, ==(ulong)(POOL_IDX_T)~0UL
64 : myele_t * mypool_ele_null ( myele_t * join ); // Location of the null element in the caller's address
65 : // space, infinite lifetime, ==NULL
66 : myele_t const * mypool_ele_null_const ( myele_t const * join ); // Const correct version of above
67 :
68 : ulong mypool_idx_sentinel ( myele_t const * join ); // Index of the sentinel element (==0)
69 : // lifetime is the pool lifetime
70 : myele_t * mypool_ele_sentinel ( myele_t * join ); // Location of the sentinel element in the caller's address
71 : // space, lifetime is the join lifetime (==join)
72 : myele_t const * mypool_ele_sentinel_const( myele_t const * join ); // Const correct version of above
73 :
74 : // Address space conversions
75 :
76 : int mypool_idx_test ( myele_t const * join, ulong idx ); // Returns 1 if idx is in [0,max) or is
77 : // mypool_idx_null. Returns zero otherwise.
78 : int mypool_ele_test ( myele_t const * join, myele_t const * ele ); // Returns 1 if ele points to a pool ele or is
79 : // NULL. Returns zero otherwise.
80 :
81 : ulong mypool_idx ( myele_t const * join, myele_t const * ele ); // Returns idx associated with ele
82 : // Assumes mypool_ele_test is 1
83 : myele_t * mypool_ele ( myele_t * join, ulong idx ); // Returns ele associated with idx
84 : // Assumes mypool_idx_test is 1
85 : // Lifetime is the local join
86 : myele_t const * mypool_ele_const( myele_t const * join, ulong idx ); // Const correct version of above
87 :
88 : // Accessors
89 :
90 : ulong mypool_max ( myele_t const * join ); // Max elements in pool in [0,IDX_NULL], [1,IDX_NULL] if POOL_SENTINEL requested
91 : ulong mypool_free( myele_t const * join ); // Number of elements free, in [0,max]
92 : ulong mypool_used( myele_t const * join ); // Number of elements currently in use / acquired, in [0,max], includes sentinel
93 : // if applicable, pool_free + pool_used == pool_max
94 :
95 : // Operations
96 :
97 : ulong mypool_idx_acquire( myele_t * join ); // Acquire an element from pool, assumes at least 1 free
98 : // Returns index of element, in [0,max) and, if applicable, not
99 : // sentinel index. Lifetime is lesser of pool lifetime and
100 : // acquired element is released. Will not return a currently
101 : // acquired element.
102 : void mypool_idx_release( myele_t * join, ulong idx ); // Release an element to pool by element idx, assumes element
103 : // currently acquired (e.g. not null index and, if applicable,
104 : // not sentinel index). Element not acquired on return.
105 :
106 : myele_t * mypool_ele_acquire( myele_t * join ); // Acquire an element from pool, assumes at least 1 free
107 : // Returns a pointer to element in caller's address space, not
108 : // NULL and, if applicable, not sentinel. Lifetime is lesser
109 : // of join lifetime and acquired element is released. Will not
110 : // return a currently acquired element
111 : void mypool_ele_release( myele_t * join, myele_t * ele ); // Release an element to pool by local pointer, assumes element
112 : // currently acquired (e.g. not NULL and, if applicable, not
113 : // sentinel). Element not acquired on return.
114 :
115 : You can do this as often as you like in a compilation unit to get
116 : different types of pools. Since it is all static inline, it is
117 : fine to do this in a header too. Additional options to fine tune
118 : this are detailed below. */
119 :
120 : #include "../bits/fd_bits.h"
121 :
122 : #ifndef POOL_NAME
123 : #error "Define POOL_NAME"
124 : #endif
125 :
126 : /* A POOL_T should be something reasonable to shallow copy
127 : with the fields described above. */
128 :
129 : #ifndef POOL_T
130 : #error "Define POOL_T"
131 : #endif
132 :
133 : /* POOL_NEXT is the name of the field the pool will clobber for
134 : elements currently not allocated. */
135 :
136 : #ifndef POOL_NEXT
137 159111555 : #define POOL_NEXT next
138 : #endif
139 :
140 : /* POOL_IDX_T is the type of the POOL_NEXT field. Should be an unsigned
141 : integer type. The maximum value this type can have is also the
142 : maximum number of elements that can be in a pool. */
143 :
144 : #ifndef POOL_IDX_T
145 : #define POOL_IDX_T ulong
146 : #endif
147 :
148 : /* If POOL_SENTINEL is non-zero, the pool will reserve element idx
149 : 0 as a sentinel element (will be considered as always allocated).
150 : Setting this also implies that the max for a pool should be at least
151 : 1. */
152 :
153 : #ifndef POOL_SENTINEL
154 : #define POOL_SENTINEL 0
155 : #endif
156 :
157 : /* 0 - local use only
158 : 1 - library header declaration
159 : 2 - library implementation */
160 :
161 : #ifndef POOL_IMPL_STYLE
162 : #define POOL_IMPL_STYLE 0
163 : #endif
164 :
165 : /* POOL_LAZY enables lazy initialization for faster startup if defined
166 : to non-zero. Decreases pool_reset cost from O(ele_max) to O(1), at
167 : the cost of more complex allocation logic (bump allocation). */
168 :
169 : #ifndef POOL_LAZY
170 : #define POOL_LAZY 0
171 : #endif
172 :
173 : /* POOL_MAGIC is the magic number that should be used to identify
174 : pools of this type in shared memory. Should be non-zero. */
175 :
176 : #ifndef POOL_MAGIC
177 12858 : #define POOL_MAGIC (0xF17EDA2CE7900100UL) /* Firedancer pool ver 0 */
178 : #endif
179 :
180 : #if FD_TMPL_USE_HANDHOLDING
181 : #include "../log/fd_log.h"
182 : #endif
183 :
184 : /* Implementation *****************************************************/
185 :
186 31247515527 : #define POOL_(n) FD_EXPAND_THEN_CONCAT3(POOL_NAME,_,n)
187 :
188 158897424 : #define POOL_IDX_NULL ((ulong)((POOL_IDX_T)~0UL))
189 :
190 : #if POOL_IMPL_STYLE==0 || POOL_IMPL_STYLE==1 /* need structures and inlines */
191 :
192 : struct POOL_(private) {
193 :
194 : ulong magic; /* ==POOL_MAGIC */
195 : ulong max; /* Max elements in pool, in [POOL_SENTINEL,POOL_IDX_NULL] */
196 : ulong free; /* Num elements in pool available, in [0,max] */
197 : ulong free_top; /* Free stack top, POOL_IDX_NULL no elements currently in pool */
198 : ulong free_lazy; /* Next free element (bump allocated) */
199 :
200 : /* max POOL_T elements here, join points to element 0 */
201 : /* element 0 will be the sentinel if POOL_SENTINEL is true */
202 :
203 : };
204 :
205 : typedef struct POOL_(private) POOL_(private_t);
206 :
207 : FD_PROTOTYPES_BEGIN
208 :
209 : /* Private APIs *******************************************************/
210 :
211 : /* pool_private_meta_footprint returns the number of bytes used by a
212 : pool metadata region */
213 :
214 : FD_FN_CONST static inline ulong
215 12935625711 : POOL_(private_meta_footprint)( void ) {
216 12935625711 : return fd_ulong_align_up( sizeof(POOL_(private_t)), fd_ulong_max( alignof(POOL_T), 128UL ) );
217 12935625711 : }
218 :
219 : /* pool_private_meta returns a pointer in the caller's address space to
220 : a pool metadata region. pool_private_meta_const is a const correct
221 : version. */
222 :
223 : FD_FN_CONST static inline POOL_(private_t) *
224 3022515492 : POOL_(private_meta)( POOL_T * join ) {
225 3022515492 : return (POOL_(private_t) *)(((ulong)join) - POOL_(private_meta_footprint)());
226 3022515492 : }
227 :
228 : FD_FN_CONST static inline POOL_(private_t) const *
229 9913016172 : POOL_(private_meta_const)( POOL_T const * join ) {
230 9913016172 : return (POOL_(private_t) const *)(((ulong)join) - POOL_(private_meta_footprint)());
231 9913016172 : }
232 :
233 : /* Public APIS ********************************************************/
234 :
235 : FD_FN_CONST static inline ulong
236 12 : POOL_(max_for_footprint)( ulong footprint ) {
237 12 : ulong meta_footprint = POOL_(private_meta_footprint)();
238 12 : if( FD_UNLIKELY( footprint <= meta_footprint ) ) return 0UL;
239 12 : return fd_ulong_min( (footprint - meta_footprint) / sizeof(POOL_T), POOL_IDX_NULL );
240 12 : }
241 :
242 : FD_FN_CONST static inline ulong
243 153522 : POOL_(align)( void ) {
244 153522 : return fd_ulong_max( alignof(POOL_T), 128UL );
245 153522 : }
246 :
247 : FD_FN_CONST static inline ulong
248 58239 : POOL_(footprint)( ulong max ) {
249 : # if POOL_SENTINEL
250 120 : if( FD_UNLIKELY( !max ) ) return 0UL;
251 114 : # endif
252 58233 : ulong align = POOL_(align)();
253 58233 : ulong meta_footprint = POOL_(private_meta_footprint)(); /* Multiple of align */
254 114 : ulong data_footprint = fd_ulong_align_up( sizeof(POOL_T)*max, align );
255 58233 : ulong thresh = fd_ulong_min( (ULONG_MAX - align - meta_footprint + 1UL) / sizeof(POOL_T), POOL_IDX_NULL );
256 114 : return fd_ulong_if( max > thresh, 0UL, meta_footprint + data_footprint );
257 58239 : }
258 :
259 : FD_PROTOTYPES_END
260 :
261 : #endif
262 :
263 : FD_PROTOTYPES_BEGIN
264 :
265 : #if POOL_IMPL_STYLE==1 /* need prototypes */
266 :
267 : FD_FN_UNUSED void * /* Work around -Winline */
268 : POOL_(new)( void * shmem,
269 : ulong max );
270 :
271 : FD_FN_UNUSED POOL_T *
272 : POOL_(join)( void * shpool );
273 :
274 : FD_FN_UNUSED void
275 : POOL_(reset)( POOL_T * join );
276 :
277 : #else /* need implementations */
278 :
279 : #if POOL_IMPL_STYLE==0 /* local only */
280 : #define POOL_IMPL_STATIC FD_FN_UNUSED static
281 : #else
282 : #define POOL_IMPL_STATIC
283 : #endif
284 :
285 : POOL_IMPL_STATIC void * /* Work around -Winline */
286 : POOL_(new)( void * shmem,
287 12879 : ulong max ) {
288 :
289 12879 : if( FD_UNLIKELY( !shmem ) ) return NULL;
290 12876 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, POOL_(align)() ) ) ) return NULL;
291 12873 : if( FD_UNLIKELY( !POOL_(footprint)( max ) ) ) return NULL;
292 :
293 12864 : POOL_T * join = (POOL_T *)(((ulong)shmem) + POOL_(private_meta_footprint)());
294 12864 : POOL_(private_t) * meta = POOL_(private_meta)( join );
295 :
296 12864 : meta->max = max;
297 12864 : meta->free = max;
298 :
299 : # if POOL_LAZY
300 1908 : meta->free_top = POOL_IDX_NULL;
301 1908 : if( FD_UNLIKELY( !max ) ) {
302 0 : meta->free_lazy = POOL_IDX_NULL; /* Not reachable if POOL_SENTINEL set (footprint test above fails) */
303 1908 : } else {
304 1908 : meta->free_lazy = 0UL;
305 : # if POOL_SENTINEL
306 : meta->free_lazy = 1UL;
307 : meta->free--;
308 : # endif
309 1908 : }
310 : # else
311 10956 : if( FD_UNLIKELY( !max ) ) meta->free_top = POOL_IDX_NULL; /* Not reachable if POOL_SENTINEL set (footprint test above fails) */
312 10947 : else {
313 10947 : meta->free_top = 0UL;
314 286447488 : for( ulong idx=1UL; idx<max; idx++ ) join[ idx-1UL ].POOL_NEXT = (POOL_IDX_T)idx;
315 10947 : join[ max-1UL ].POOL_NEXT = (POOL_IDX_T)POOL_IDX_NULL;
316 :
317 : # if POOL_SENTINEL
318 : meta->free_top = 1UL;
319 : meta->free--;
320 27 : join[ 0 ].POOL_NEXT = (POOL_IDX_T)POOL_IDX_NULL;
321 : # endif
322 10947 : }
323 : # endif
324 :
325 12864 : FD_COMPILER_MFENCE();
326 12864 : FD_VOLATILE( meta->magic ) = (POOL_MAGIC);
327 12864 : FD_COMPILER_MFENCE();
328 :
329 12864 : return shmem;
330 12873 : }
331 :
332 : POOL_IMPL_STATIC void
333 4194 : POOL_(reset)( POOL_T * join ) {
334 4194 : POOL_(private_t) * meta = POOL_(private_meta)( join );
335 :
336 4194 : meta->free = meta->max;
337 :
338 : # if POOL_LAZY
339 2484 : meta->free_top = POOL_IDX_NULL;
340 2484 : if( FD_UNLIKELY( !meta->max ) ) {
341 0 : meta->free_lazy = POOL_IDX_NULL; /* Not reachable if POOL_SENTINEL set (footprint test above fails) */
342 2484 : } else {
343 2484 : meta->free_lazy = 0UL;
344 : # if POOL_SENTINEL
345 : meta->free_lazy = 1UL;
346 : meta->free--;
347 : # endif
348 2484 : }
349 : # else
350 1710 : if( FD_UNLIKELY( !meta->max ) ) meta->free_top = POOL_IDX_NULL; /* Not reachable if POOL_SENTINEL set (footprint test above fails) */
351 1710 : else {
352 1710 : meta->free_top = 0UL;
353 236292 : for( ulong idx=1UL; idx<meta->max; idx++ ) join[ idx-1UL ].POOL_NEXT = (POOL_IDX_T)idx;
354 1710 : join[ meta->max-1UL ].POOL_NEXT = (POOL_IDX_T)POOL_IDX_NULL;
355 :
356 : # if POOL_SENTINEL
357 : meta->free_top = 1UL;
358 : meta->free--;
359 : join[ 0 ].POOL_NEXT = (POOL_IDX_T)POOL_IDX_NULL;
360 : # endif
361 1710 : }
362 : # endif
363 4194 : }
364 :
365 : POOL_IMPL_STATIC POOL_T *
366 14874 : POOL_(join)( void * shpool ) {
367 14874 : if( FD_UNLIKELY( !shpool ) ) return NULL;
368 14871 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shpool, POOL_(align)() ) ) ) return NULL;
369 :
370 14868 : POOL_T * join = (POOL_T *)(((ulong)shpool) + POOL_(private_meta_footprint)());
371 14868 : POOL_(private_t) * meta = POOL_(private_meta)( join );
372 :
373 14868 : if( FD_UNLIKELY( FD_VOLATILE_CONST( meta->magic )!=(POOL_MAGIC) ) ) return NULL;
374 :
375 14865 : return join;
376 14868 : }
377 :
378 : #endif
379 :
380 : FD_PROTOTYPES_END
381 :
382 : FD_PROTOTYPES_BEGIN
383 :
384 : #if POOL_IMPL_STYLE==0 || POOL_IMPL_STYLE==1 /* need structures and inlines */
385 :
386 : FD_FN_CONST static inline void *
387 4389 : POOL_(leave)( POOL_T * join ) {
388 4389 : if( FD_UNLIKELY( !join ) ) return NULL;
389 4386 : return (void *)(((ulong)join) - POOL_(private_meta_footprint)());
390 4389 : }
391 :
392 : static inline void *
393 3690 : POOL_(delete)( void * shpool ) {
394 3690 : if( FD_UNLIKELY( !shpool ) ) return NULL;
395 3687 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shpool, POOL_(align)() ) ) ) return NULL;
396 :
397 3684 : POOL_T * join = (POOL_T *)(((ulong)shpool) + POOL_(private_meta_footprint)());
398 3684 : POOL_(private_t) * meta = POOL_(private_meta)( join );
399 :
400 3684 : if( FD_UNLIKELY( FD_VOLATILE_CONST( meta->magic )!=(POOL_MAGIC) ) ) return NULL;
401 :
402 3681 : FD_COMPILER_MFENCE();
403 3681 : FD_VOLATILE( meta->magic ) = 0UL;
404 3681 : FD_COMPILER_MFENCE();
405 :
406 3681 : return shpool;
407 3684 : }
408 :
409 : /* Special values */
410 :
411 21822 : FD_FN_CONST static inline ulong POOL_(idx_null) ( POOL_T const * join ) { (void)join; return POOL_IDX_NULL; }
412 3 : FD_FN_CONST static inline POOL_T * POOL_(ele_null) ( POOL_T * join ) { (void)join; return NULL; }
413 3 : FD_FN_CONST static inline POOL_T const * POOL_(ele_null_const) ( POOL_T const * join ) { (void)join; return NULL; }
414 :
415 : #if POOL_SENTINEL
416 3 : FD_FN_CONST static inline ulong POOL_(idx_sentinel) ( POOL_T const * join ) { (void)join; return 0UL; }
417 9 : FD_FN_CONST static inline POOL_T * POOL_(ele_sentinel) ( POOL_T * join ) { return join; }
418 3 : FD_FN_CONST static inline POOL_T const * POOL_(ele_sentinel_const)( POOL_T const * join ) { return join; }
419 : #endif
420 :
421 : /* Address space conversion */
422 :
423 : FD_FN_PURE static inline int
424 : POOL_(idx_test)( POOL_T const * join,
425 152328195 : ulong idx ) {
426 152328195 : ulong max = POOL_(private_meta_const)( join )->max;
427 152328195 : return (idx<max) | (idx==POOL_IDX_NULL);
428 152328195 : }
429 :
430 : FD_FN_PURE static inline int
431 : POOL_(ele_test)( POOL_T const * join,
432 7046803065 : POOL_T const * ele ) {
433 7046803065 : ulong max = POOL_(private_meta_const)( join )->max;
434 7046803065 : ulong idx = (ulong)(ele - join);
435 7046803065 : FD_COMPILER_FORGET( idx ); /* prevent compiler from optimizing out alignment test */
436 7046803065 : return (!ele) | ((idx<max) & ((ulong)ele==((ulong)join+(idx*sizeof(POOL_T))))); /* last test checks alignment */
437 7046803065 : }
438 :
439 : FD_FN_CONST static inline ulong
440 : POOL_(idx)( POOL_T const * join,
441 301693197 : POOL_T const * ele ) {
442 : # if FD_TMPL_USE_HANDHOLDING
443 : if( FD_UNLIKELY( !POOL_(ele_test)( join, ele ) ) ) FD_LOG_CRIT(( "no such element" ));
444 : # endif
445 301693197 : return ele ? (ulong)(ele-join) : POOL_IDX_NULL;
446 301693197 : }
447 :
448 : FD_FN_CONST static inline POOL_T *
449 : POOL_(ele)( POOL_T * join,
450 3461475 : ulong idx ) {
451 : # if FD_TMPL_USE_HANDHOLDING
452 : if( FD_UNLIKELY( !POOL_(idx_test)( join, idx ) ) ) FD_LOG_CRIT(( "no such index" ));
453 : # endif
454 3461475 : return (idx==POOL_IDX_NULL) ? NULL : (join + idx);
455 3461475 : }
456 :
457 : FD_FN_CONST static inline POOL_T const *
458 : POOL_(ele_const)( POOL_T const * join,
459 2994693 : ulong idx ) {
460 : # if FD_TMPL_USE_HANDHOLDING
461 : if( FD_UNLIKELY( !POOL_(idx_test)( join, idx ) ) ) FD_LOG_CRIT(( "no such index" ));
462 : # endif
463 2994693 : return (idx==POOL_IDX_NULL) ? NULL : (join + idx);
464 2994693 : }
465 :
466 : /* Accessors */
467 :
468 3964653 : FD_FN_PURE static inline ulong POOL_(max) ( POOL_T const * join ) { return POOL_(private_meta_const)( join )->max; }
469 1191129165 : FD_FN_PURE static inline ulong POOL_(free)( POOL_T const * join ) { return POOL_(private_meta_const)( join )->free; }
470 :
471 : FD_FN_PURE static inline ulong
472 1518791094 : POOL_(used)( POOL_T const * join ) {
473 1518791094 : POOL_(private_t) const * meta = POOL_(private_meta_const)( join );
474 1518791094 : return meta->max - meta->free;
475 1518791094 : }
476 :
477 : /* Operations */
478 :
479 : static inline ulong
480 1511803689 : POOL_(idx_acquire)( POOL_T * join ) {
481 1511803689 : POOL_(private_t) * meta = POOL_(private_meta)( join );
482 : # if FD_TMPL_USE_HANDHOLDING
483 : if( FD_UNLIKELY( !meta->free ) ) FD_LOG_CRIT(( "pool is full" ));
484 : # endif
485 1511803689 : ulong idx = meta->free_top;
486 : # if POOL_LAZY
487 149342667 : if( FD_UNLIKELY( idx==POOL_IDX_NULL ) ) {
488 2616 : idx = meta->free_lazy;
489 2616 : ulong nxt = idx + 1UL;
490 2616 : meta->free_lazy = ( nxt<meta->max ) ? nxt : POOL_IDX_NULL;
491 149340051 : } else {
492 149340051 : meta->free_top = (ulong)join[ idx ].POOL_NEXT;
493 149340051 : }
494 : # else
495 1362461022 : meta->free_top = (ulong)join[ idx ].POOL_NEXT;
496 : # endif
497 1511803689 : meta->free--;
498 1511803689 : return idx;
499 1511803689 : }
500 :
501 : static inline void
502 : POOL_(idx_release)( POOL_T * join,
503 1510676193 : ulong idx ) {
504 1510676193 : POOL_(private_t) * meta = POOL_(private_meta)( join );
505 : # if FD_TMPL_USE_HANDHOLDING
506 : if( FD_UNLIKELY( (meta->max<=idx) | (idx==POOL_IDX_NULL) ) ) FD_LOG_CRIT(( "invalid index" ));
507 : # if POOL_SENTINEL
508 : if( FD_UNLIKELY( POOL_(idx_sentinel)( join )==idx ) ) FD_LOG_CRIT(( "cannot releaes sentinel" ));
509 : if( FD_UNLIKELY( meta->free>=meta->max-1 ) ) FD_LOG_CRIT(( "pool is empty" ));
510 : # else
511 : if( FD_UNLIKELY( meta->free>=meta->max ) ) FD_LOG_CRIT(( "pool is empty" ));
512 : # endif
513 : # endif
514 1510676193 : join[ idx ].POOL_NEXT = (POOL_IDX_T)meta->free_top;
515 1510676193 : meta->free_top = idx;
516 1510676193 : meta->free++;
517 1510676193 : }
518 :
519 424791030 : static inline POOL_T * POOL_(ele_acquire)( POOL_T * join ) { return join + POOL_(idx_acquire)( join ); }
520 410202303 : static inline void POOL_(ele_release)( POOL_T * join, POOL_T * ele ) { POOL_(idx_release)( join, (ulong)(ele - join) ); }
521 :
522 : /* TODO: consider zeroing out pool mem on new? */
523 :
524 : /* TODO: consider providing element size and alignment as metadata? */
525 :
526 : /* TODO: consider lockfree concurrent version with ABA tagged free_top? */
527 :
528 : /* TODO: consider a verify and rebuild that work via most sig bit of
529 : POOL_NEXT for element marking (the POOL_NEXT field in the structure
530 : would have to become dedicated to the pool though). */
531 :
532 : #endif
533 :
534 : FD_PROTOTYPES_END
535 :
536 : #undef POOL_IMPL_STATIC
537 : #undef POOL_IDX_NULL
538 : #undef POOL_
539 :
540 : #undef POOL_MAGIC
541 : #undef POOL_LAZY
542 : #undef POOL_SENTINEL
543 : #undef POOL_IDX_T
544 : #undef POOL_NEXT
545 : #undef POOL_IMPL_STYLE
546 : #undef POOL_T
547 : #undef POOL_NAME
|