Line data Source code
1 : /* Generate prototypes, inlines and/or implementations for HPC slingly
2 : linked lists. A slist can store a practically unbounded number of
3 : elements. Typical slist operations are generally a fast O(1) time
4 : and slist element memory overhead is a small O(1) space.
5 :
6 : This API is designed for ultra tight coupling with pools, treaps,
7 : heaps, maps, dlists, etc. Likewise, a slist can be persisted beyond
8 : the lifetime of the creating process, used concurrently in many
9 : common operations, used inter-process, relocated in memory, naively
10 : serialized/deserialized, moved between hosts, supports index
11 : compression for cache and memory bandwidth efficiency, etc.
12 :
13 : Memory efficiency and flexible footprint are prioritized.
14 :
15 : Typical usage:
16 :
17 : struct myele {
18 : ulong next; // Technically "SLIST_IDX_T SLIST_NEXT" (default is ulong next), do not modify while element is in the slist
19 : ... next can be located arbitrarily in the element and can be
20 : ... reused for other purposes when the element is not in a slist.
21 : ... An element should not be moved / released while an element is
22 : ... in a slist
23 : };
24 :
25 : typedef struct myele myele_t;
26 :
27 : #define SLIST_NAME myslist
28 : #define SLIST_ELE_T myele_t
29 : #include "tmpl/fd_slist.c"
30 :
31 : will declare the following APIs as a header only style library in the
32 : compilation unit:
33 :
34 : // myslist_ele_max returns the theoretical maximum number of
35 : // elements that can be held in a myslist.
36 :
37 : ulong myslist_ele_max( void );
38 :
39 : // myslist_{align,footprint} returns the alignment and footprint
40 : // needed for a memory region to be used as a myslist. align will
41 : // be an integer power-of-two and footprint will be a multiple of
42 : // align. The values will be compile-time declaration friendly
43 : // (e.g. "myslist_t mem[1];" will have the correct alignment and
44 : // footprint and not be larger than 4096).
45 : //
46 : // myslist_new formats a memory region with the appropriate
47 : // alignment and footprint whose first byte in the caller's address
48 : // space is pointed to by shmem as a myslist. Returns shmem on
49 : // success and NULL on failure (logs details). Caller is not
50 : // joined on return. The slist will be empty.
51 : //
52 : // myslist_join joins a myslist. Assumes shslist points at a
53 : // memory region formatted as a myslist in the caller's address
54 : // space. Returns a handle to the caller's local join on success
55 : // and NULL on failure (logs details). Do not assume this is a
56 : // simple cast of shslist!
57 : //
58 : // myslist_leave leaves a myslist. Assumes join points to a
59 : // current local join. Returns shslist used on join. Do not
60 : // assume this is a simple cast of join!
61 : //
62 : // myslist_delete unformats a memory region used as a myslist.
63 : // Assumes shslist points to a memory region in the caller's local
64 : // address space formatted as a myslist, that there are no joins to
65 : // the myslist and that any application cleanup of the entries has
66 : // already been done. Returns shslist on success and NULL on
67 : // failure.
68 :
69 : ulong myslist_align ( void );
70 : ulong myslist_footprint( void );
71 : void * myslist_new ( void * shmem );
72 : myslist_t * myslist_join ( void * shslist );
73 : void * myslist_leave ( myslist_t * join );
74 : void * myslist_delete ( void * shslist );
75 :
76 : // The below APIs assume join is a current local join to a myslist
77 : // and pool is a current local join to the element storage backing
78 : // the slist.
79 : //
80 : // myslist_is_empty returns 1 if the slist is empty and 0
81 : // otherwise.
82 : //
83 : // myslist_idx_peek_{head,tail} returns the pool index of the
84 : // slist's {head,tail}. Assumes slist is not empty.
85 :
86 : int myslist_is_empty( myslist_t const * join, myele_t const * pool );
87 :
88 : ulong myslist_idx_peek_head( myslist_t const * join, myele_t const * pool );
89 : ulong myslist_idx_peek_tail( myslist_t const * join, myele_t const * pool );
90 :
91 : // myslist_idx_push_{head,tail} pushes the pool element whose index
92 : // is ele_idx to the slist's {head,tail} and returns join. Assumes
93 : // ele_idx valid and not already in the slist.
94 : // myslist_idx_pop_head pops the pool element at the slist's head
95 : // and returns its pool index. Assumes slist is not empty.
96 : //
97 : // myslist_idx_insert_after inserts the pool element whose index is
98 : // ele_idx into the slist immediately after the pool element whose
99 : // index is prev_idx and returns join. Assumes ele_idx is valid
100 : // and not already in the slist and prev_idx is already in the
101 : // slist.
102 :
103 : myslist_t * myslist_idx_push_head ( myslist_t * join, ulong ele_idx, myele_t * pool );
104 : myslist_t * myslist_idx_push_tail ( myslist_t * join, ulong ele_idx, myele_t * pool );
105 : ulong myslist_idx_pop_head ( myslist_t * join, myele_t * pool );
106 : myslist_t * myslist_idx_insert_after ( myslist_t * join, ulong ele_idx, ulong prev_idx, myele_t * pool );
107 :
108 : // myslist_remove_all removes all elements from the slist and
109 : // returns join. It is the caller's responsibility to release all
110 : // elements to the pool as might be necessary.
111 :
112 : myslist_t * myslist_remove_all( myslist_t * join, myele_t * pool );
113 :
114 : // myslist_iter_* support fast ordered forward (head to tail)
115 : // iteration over all the elements in a slist. Example usage:
116 : //
117 : // for( myslist_iter_t iter = myslist_iter_init( join, pool );
118 : // !myslist_iter_done( iter, join, pool );
119 : // iter = myslist_iter_next( iter, join, pool ) ) {
120 : // ulong ele_idx = myslist_iter_idx( iter, join, pool );
121 : //
122 : // ... process element here
123 : //
124 : // ... IMPORTANT! It is generally safe to insert elements
125 : // ... here (though they might not be covered by this
126 : // ... iteration). It is also generally safe to remove any
127 : // ... element but the current element here (the removed
128 : // ... element might have already been iterated over). It is
129 : // ... straightforward to make a variant of this iterator
130 : // ... that would support removing the current element here
131 : // ... if desired.
132 : // }
133 :
134 : struct myslist_iter_private { ... internal use only ... };
135 : typedef struct myslist_iter_private myslist_iter_t;
136 :
137 : myslist_iter_t myslist_iter_init( myslist_t const * join, myele_t const * pool );
138 : int myslist_iter_done( myslist_iter_t iter, myslist_t const * join, myele_t const * pool );
139 : myslist_iter_t myslist_iter_next( myslist_iter_t iter, myslist_t const * join, myele_t const * pool ); // assumes !done
140 : ulong myslist_iter_idx ( myslist_iter_t iter, myslist_t const * join, myele_t const * pool ); // assumes !done
141 :
142 : // myslist_verify returns 0 if the myslist is not obviously corrupt
143 : // or -1 (i.e. ERR_INVAL) otherwise (logs details).
144 :
145 : int
146 : myslist_verify( myslist_t const * join, // Current local join to a myslist.
147 : ulong ele_cnt, // Element storage size, in [0,myslist_ele_max()]
148 : myele_t const * pool ); // Current local join to element storage, indexed [0,ele_cnt)
149 :
150 : // The above APIs have helpers that operate purely in the caller's
151 : // local address space when applicable. The various elements
152 : // passed to / returned from these functions should be / will be
153 : // from the slist's underlying pool.
154 :
155 : myele_t * myslist_ele_peek_head( myslist_t const * join, myele_t * pool );
156 : myele_t * myslist_ele_peek_tail( myslist_t const * join, myele_t * pool );
157 :
158 : myslist_t * myslist_ele_push_head ( myslist_t * join, myele_t * ele, myele_t * pool );
159 : myslist_t * myslist_ele_push_tail ( myslist_t * join, myele_t * ele, myele_t * pool );
160 : myele_t * myslist_ele_pop_head ( myslist_t * join, myele_t * pool );
161 : myslist_t * myslist_ele_insert_after ( myslist_t * join, myele_t * ele, myele_t * prev, myele_t * pool );
162 :
163 : myele_t * myslist_iter_ele( myslist_iter_t iter, myslist_t const * join, myele_t * pool );
164 :
165 : // ... and const correct helpers when applicable
166 :
167 : myele_t const * myslist_ele_peek_head_const( myslist_t const * join, myele_t const * pool );
168 : myele_t const * myslist_ele_peek_tail_const( myslist_t const * join, myele_t const * pool );
169 :
170 : myele_t const * myslist_iter_ele_const( myslist_iter_t iter, myslist_t const * join, myele_t const * pool );
171 :
172 : You can do this as often as you like in a compilation unit to get
173 : different types of slists. Variants exist for making header
174 : prototypes only and/or implementations only if making a library for
175 : use across multiple compilation units. Further, options exist to use
176 : different hashing functions, comparison functions, etc as detailed
177 : below. */
178 :
179 : /* TODO: DOC CONCURRENCY REQUIREMENTS */
180 :
181 : /* SLIST_NAME gives the API prefix to use for a slist */
182 :
183 : #ifndef SLIST_NAME
184 : #error "Define SLIST_NAME"
185 : #endif
186 :
187 : /* SLIST_ELE_T is the slist element type. */
188 :
189 : #ifndef SLIST_ELE_T
190 : #error "Define SLIST_ELE_T"
191 : #endif
192 :
193 : /* SLIST_IDX_T is the type used for the next field in the SLIST_ELE_T.
194 : Should be a primitive unsigned integer type. Defaults to ulong. A
195 : slist can't use element memory regions with more elements than the
196 : maximum value that can be represented by a SLIST_IDX_T. (E.g. if
197 : ushort, the maximum size element store supported by the slist is
198 : 65535 elements.) */
199 :
200 : #ifndef SLIST_IDX_T
201 : #define SLIST_IDX_T ulong
202 : #endif
203 :
204 : /* SLIST_NEXT is the SLIST_ELE_T next field */
205 :
206 : #ifndef SLIST_NEXT
207 : #define SLIST_NEXT next
208 : #endif
209 :
210 : /* SLIST_MAGIC is the magic number to use for the structure to aid in
211 : persistent and/or IPC usage. */
212 :
213 : #ifndef SLIST_MAGIC
214 12039 : #define SLIST_MAGIC (0xf17eda2c37371570UL) /* firedancer slist version 0 */
215 : #endif
216 :
217 : /* 0 - local use only
218 : 1 - library header declaration
219 : 2 - library implementation */
220 :
221 : #ifndef SLIST_IMPL_STYLE
222 : #define SLIST_IMPL_STYLE 0
223 : #endif
224 :
225 : #if FD_TMPL_USE_HANDHOLDING
226 : #include "../log/fd_log.h"
227 : #endif
228 :
229 : /* Implementation *****************************************************/
230 :
231 : /* Constructors and verification log details on failure (rest only needs
232 : fd_bits.h, consider making logging a compile time option). */
233 :
234 45509733114 : #define SLIST_(n) FD_EXPAND_THEN_CONCAT3(SLIST_NAME,_,n)
235 :
236 : #if SLIST_IMPL_STYLE==0 || SLIST_IMPL_STYLE==1 /* need structures and inlines */
237 :
238 : struct SLIST_(private) {
239 :
240 : /* join points here */
241 :
242 : ulong magic; /* == SLIST_MAGIC */
243 : SLIST_IDX_T head; /* index of first list element (or idx_null if empty list) */
244 : SLIST_IDX_T tail; /* index of last list element (or idx_null if empty list) */
245 : };
246 :
247 : typedef struct SLIST_(private) SLIST_(private_t);
248 :
249 : typedef SLIST_(private_t) SLIST_(t);
250 :
251 : typedef ulong SLIST_(iter_t);
252 :
253 : FD_PROTOTYPES_BEGIN
254 :
255 : /* slist_private returns the location of the slist header for a current
256 : local join. Assumes join is a current local join.
257 : slist_private_const is a const correct version. */
258 :
259 : FD_FN_CONST static inline SLIST_(private_t) *
260 375803571 : SLIST_(private)( SLIST_(t) * join ) {
261 375803571 : return (SLIST_(private_t) *)join;
262 375803571 : }
263 :
264 : FD_FN_CONST static inline SLIST_(private_t) const *
265 13688298153 : SLIST_(private_const)( SLIST_(t) const * join ) {
266 13688298153 : return (SLIST_(private_t) const *)join;
267 13688298153 : }
268 :
269 : /* slist_private_{cidx,idx} compress / decompress 64-bit in-register
270 : indices to/from their in-memory representations. */
271 :
272 939533067 : FD_FN_CONST static inline SLIST_IDX_T SLIST_(private_cidx)( ulong idx ) { return (SLIST_IDX_T)idx; }
273 17064695904 : FD_FN_CONST static inline ulong SLIST_(private_idx) ( SLIST_IDX_T cidx ) { return (ulong) cidx; }
274 :
275 : /* slist_private_idx_null returns the element storage index that
276 : represents NULL. */
277 :
278 438401679 : FD_FN_CONST static inline ulong SLIST_(private_idx_null)( void ) { return (ulong)(SLIST_IDX_T)~0UL; }
279 :
280 : /* slist_private_idx_is_null returns 1 if idx is the NULL slist index
281 : and 0 otherwise. */
282 :
283 5439137136 : FD_FN_CONST static inline int SLIST_(private_idx_is_null)( ulong idx ) { return idx==(ulong)(SLIST_IDX_T)~0UL; }
284 :
285 187540266 : FD_FN_CONST static inline ulong SLIST_(ele_max)( void ) { return (ulong)(SLIST_IDX_T)~0UL; }
286 :
287 : FD_FN_PURE static inline int
288 : SLIST_(is_empty)( SLIST_(t) const * join,
289 1875721860 : SLIST_ELE_T const * pool ) {
290 1875721860 : (void)pool;
291 1875721860 : return SLIST_(private_idx_is_null)( SLIST_(private_idx)( SLIST_(private_const)( join )->head ) );
292 1875721860 : }
293 :
294 : FD_FN_PURE static inline ulong
295 : SLIST_(idx_peek_head)( SLIST_(t) const * join,
296 5625844290 : SLIST_ELE_T const * pool ) {
297 5625844290 : (void)pool;
298 : # if FD_TMPL_USE_HANDHOLDING
299 : if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot peek on empty slist" ));
300 : # endif
301 5625844290 : return SLIST_(private_idx)( SLIST_(private_const)( join )->head );
302 5625844290 : }
303 :
304 : FD_FN_PURE static inline ulong
305 : SLIST_(idx_peek_tail)( SLIST_(t) const * join,
306 5624272518 : SLIST_ELE_T const * pool ) {
307 5624272518 : (void)pool;
308 : # if FD_TMPL_USE_HANDHOLDING
309 : if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot peek on empty slist" ));
310 : # endif
311 5624272518 : return SLIST_(private_idx)( SLIST_(private_const)( join )->tail );
312 5624272518 : }
313 :
314 : static inline SLIST_(t) *
315 : SLIST_(idx_push_head)( SLIST_(t) * join,
316 : ulong ele_idx,
317 62499201 : SLIST_ELE_T * pool ) {
318 62499201 : SLIST_(private_t) * slist = SLIST_(private)( join );
319 :
320 62499201 : ulong head_idx = SLIST_(private_idx)( slist->head );
321 :
322 62499201 : pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( head_idx );
323 :
324 62499201 : SLIST_IDX_T dummy[1];
325 62499201 : *fd_ptr_if( !SLIST_(private_idx_is_null)( head_idx ), dummy+0, &slist->tail ) =
326 62499201 : SLIST_(private_cidx)( ele_idx );
327 :
328 62499201 : slist->head = SLIST_(private_cidx)( ele_idx );
329 62499201 : return join;
330 62499201 : }
331 :
332 : static inline SLIST_(t) *
333 : SLIST_(idx_push_tail)( SLIST_(t) * join,
334 : ulong ele_idx,
335 62935587 : SLIST_ELE_T * pool ) {
336 62935587 : SLIST_(private_t) * slist = SLIST_(private)( join );
337 :
338 62935587 : ulong tail_idx = SLIST_(private_idx)( slist->tail );
339 :
340 62935587 : pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
341 :
342 62935587 : *fd_ptr_if( !SLIST_(private_idx_is_null)( tail_idx ), &pool[ tail_idx ].SLIST_NEXT, &slist->head ) =
343 62935587 : SLIST_(private_cidx)( ele_idx );
344 :
345 62935587 : slist->tail = SLIST_(private_cidx)( ele_idx );
346 62935587 : return join;
347 62935587 : }
348 :
349 : static inline ulong
350 : SLIST_(idx_pop_head)( SLIST_(t) * join,
351 187901697 : SLIST_ELE_T * pool ) {
352 : # if FD_TMPL_USE_HANDHOLDING
353 : if( FD_UNLIKELY( SLIST_(is_empty)( join, pool ) ) ) FD_LOG_CRIT(( "cannot pop from empty slist" ));
354 : # endif
355 187901697 : SLIST_(private_t) * slist = SLIST_(private)( join );
356 :
357 187901697 : ulong ele_idx = SLIST_(private_idx)( slist->head ); /* Not NULL as per contract */
358 187901697 : ulong next_idx = SLIST_(private_idx)( pool[ ele_idx ].SLIST_NEXT );
359 :
360 187901697 : SLIST_IDX_T dummy[1];
361 187901697 : *fd_ptr_if( !SLIST_(private_idx_is_null)( next_idx ), dummy+0, &slist->tail ) =
362 187901697 : SLIST_(private_cidx)( SLIST_(private_idx_null)() );
363 :
364 187901697 : slist->head = SLIST_(private_cidx)( next_idx );
365 187901697 : return ele_idx;
366 187901697 : }
367 :
368 : static inline SLIST_(t) *
369 : SLIST_(idx_insert_after)( SLIST_(t) * join,
370 : ulong ele_idx,
371 : ulong prev_idx,
372 62467059 : SLIST_ELE_T * pool ) {
373 62467059 : ulong next_idx = SLIST_(private_idx)( pool[ prev_idx ].SLIST_NEXT );
374 :
375 62467059 : pool[ ele_idx ].SLIST_NEXT = SLIST_(private_cidx)( next_idx );
376 :
377 62467059 : pool[ prev_idx ].SLIST_NEXT = SLIST_(private_cidx)( ele_idx );
378 :
379 62467059 : SLIST_IDX_T dummy[1];
380 62467059 : *fd_ptr_if( !SLIST_(private_idx_is_null)( next_idx ), dummy+0, &SLIST_(private)( join )->tail ) =
381 62467059 : SLIST_(private_cidx)( ele_idx );
382 :
383 62467059 : return join;
384 62467059 : }
385 :
386 : static inline SLIST_(t) *
387 : SLIST_(remove_all)( SLIST_(t) * join,
388 27 : SLIST_ELE_T * pool ) {
389 27 : (void)pool;
390 27 : SLIST_(private_t) * slist = SLIST_(private)( join );
391 27 : slist->head = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
392 27 : slist->tail = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
393 27 : return join;
394 27 : }
395 :
396 : FD_FN_PURE static inline SLIST_(iter_t)
397 : SLIST_(iter_init)( SLIST_(t) const * join,
398 374919222 : SLIST_ELE_T const * pool ) {
399 374919222 : (void)pool;
400 374919222 : return SLIST_(private_idx)( SLIST_(private_const)( join )->head );
401 374919222 : }
402 :
403 : FD_FN_CONST static inline int
404 : SLIST_(iter_done)( SLIST_(iter_t) iter,
405 : SLIST_(t) const * join,
406 1593543513 : SLIST_ELE_T const * pool ) {
407 1593543513 : (void)join; (void)pool;
408 1593543513 : return SLIST_(private_idx_is_null)( iter );
409 1593543513 : }
410 :
411 : FD_FN_PURE static inline SLIST_(iter_t)
412 : SLIST_(iter_next)( SLIST_(iter_t) iter,
413 : SLIST_(t) const * join,
414 1218624291 : SLIST_ELE_T const * pool ) {
415 1218624291 : (void)join;
416 1218624291 : return SLIST_(private_idx)( pool[ iter ].SLIST_NEXT );
417 1218624291 : }
418 :
419 : FD_FN_CONST static inline ulong
420 : SLIST_(iter_idx)( SLIST_(iter_t) iter,
421 : SLIST_(t) const * join,
422 187489653 : SLIST_ELE_T const * pool ) {
423 187489653 : (void)join; (void)pool;
424 187489653 : return iter;
425 187489653 : }
426 :
427 : FD_FN_PURE static inline SLIST_ELE_T *
428 : SLIST_(ele_peek_head)( SLIST_(t) const * join,
429 1876591440 : SLIST_ELE_T * pool ) {
430 1876591440 : return pool + SLIST_(idx_peek_head)( join, pool );
431 1876591440 : }
432 :
433 : FD_FN_PURE static inline SLIST_ELE_T const *
434 : SLIST_(ele_peek_head_const)( SLIST_(t) const * join,
435 1874626416 : SLIST_ELE_T const * pool ) {
436 1874626416 : return pool + SLIST_(idx_peek_head)( join, pool );
437 1874626416 : }
438 :
439 : FD_FN_PURE static inline SLIST_ELE_T *
440 : SLIST_(ele_peek_tail)( SLIST_(t) const * join,
441 1875019686 : SLIST_ELE_T * pool ) {
442 1875019686 : return pool + SLIST_(idx_peek_tail)( join, pool );
443 1875019686 : }
444 :
445 : FD_FN_PURE static inline SLIST_ELE_T const *
446 : SLIST_(ele_peek_tail_const)( SLIST_(t) const * join,
447 1874626416 : SLIST_ELE_T const * pool ) {
448 1874626416 : return pool + SLIST_(idx_peek_tail)( join, pool );
449 1874626416 : }
450 :
451 : static inline SLIST_(t) *
452 : SLIST_(ele_push_head)( SLIST_(t) * join,
453 : SLIST_ELE_T * ele,
454 31246809 : SLIST_ELE_T * pool ) {
455 31246809 : return SLIST_(idx_push_head)( join, (ulong)(ele-pool), pool );
456 31246809 : }
457 :
458 : static inline SLIST_(t) *
459 : SLIST_(ele_push_tail)( SLIST_(t) * join,
460 : SLIST_ELE_T * ele,
461 31680603 : SLIST_ELE_T * pool ) {
462 31680603 : return SLIST_(idx_push_tail)( join, (ulong)(ele-pool), pool );
463 31680603 : }
464 :
465 : static inline SLIST_ELE_T *
466 : SLIST_(ele_pop_head)( SLIST_(t) * join,
467 93740538 : SLIST_ELE_T * pool ) {
468 93740538 : return pool + SLIST_(idx_pop_head)( join, pool );
469 93740538 : }
470 :
471 : static inline SLIST_(t) *
472 : SLIST_(ele_insert_after)( SLIST_(t) * join,
473 : SLIST_ELE_T * ele,
474 : SLIST_ELE_T * prev,
475 31229655 : SLIST_ELE_T * pool ) {
476 31229655 : return SLIST_(idx_insert_after)( join, (ulong)(ele-pool), (ulong)(prev-pool), pool );
477 31229655 : }
478 :
479 : FD_FN_CONST static inline SLIST_ELE_T *
480 : SLIST_(iter_ele)( SLIST_(iter_t) iter,
481 : SLIST_(t) const * join,
482 187429599 : SLIST_ELE_T * pool ) {
483 187429599 : (void)join;
484 187429599 : return pool + iter;
485 187429599 : }
486 :
487 : FD_FN_CONST static inline SLIST_ELE_T const *
488 : SLIST_(iter_ele_const)( SLIST_(iter_t) iter,
489 : SLIST_(t) const * join,
490 0 : SLIST_ELE_T const * pool ) {
491 0 : (void)join;
492 0 : return pool + iter;
493 0 : }
494 :
495 : FD_PROTOTYPES_END
496 :
497 : #endif
498 :
499 : #if SLIST_IMPL_STYLE==1 /* need prototypes */
500 :
501 : FD_PROTOTYPES_BEGIN
502 :
503 : FD_FN_CONST ulong SLIST_(align) ( void );
504 : FD_FN_CONST ulong SLIST_(footprint)( void );
505 : void * SLIST_(new) ( void * shmem );
506 : SLIST_(t) * SLIST_(join) ( void * shslist );
507 : void * SLIST_(leave) ( SLIST_(t) * join );
508 : void * SLIST_(delete) ( void * shslist );
509 :
510 : int
511 : SLIST_(verify)( SLIST_(t) const * join,
512 : ulong ele_cnt,
513 : SLIST_ELE_T const * pool );
514 :
515 : FD_PROTOTYPES_END
516 :
517 : #else /* need implementations */
518 :
519 : #if SLIST_IMPL_STYLE==0 /* local only */
520 : #define SLIST_IMPL_STATIC FD_FN_UNUSED static
521 : #else
522 : #define SLIST_IMPL_STATIC
523 : #endif
524 :
525 : FD_PROTOTYPES_BEGIN
526 :
527 36132 : FD_FN_CONST SLIST_IMPL_STATIC ulong SLIST_(align) ( void ) { return alignof(SLIST_(t)); }
528 3 : FD_FN_CONST SLIST_IMPL_STATIC ulong SLIST_(footprint)( void ) { return sizeof( SLIST_(t)); }
529 :
530 : SLIST_IMPL_STATIC void *
531 12045 : SLIST_(new)( void * shmem ) {
532 :
533 12045 : if( FD_UNLIKELY( !shmem ) ) {
534 3 : FD_LOG_WARNING(( "NULL shmem" ));
535 3 : return NULL;
536 3 : }
537 :
538 12042 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, SLIST_(align)() ) ) ) {
539 3 : FD_LOG_WARNING(( "misaligned shmem" ));
540 3 : return NULL;
541 3 : }
542 :
543 : // Note: Guaranteed non-zero and not otherwise used
544 : //ulong footprint = SLIST_(footprint)();
545 : //if( FD_UNLIKELY( !footprint ) ) {
546 : // FD_LOG_WARNING(( "bad footprint" ));
547 : // return NULL;
548 : //}
549 :
550 12039 : SLIST_(private_t) * slist = (SLIST_(private_t) *)shmem;
551 :
552 12039 : slist->head = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
553 12039 : slist->tail = SLIST_(private_cidx)( SLIST_(private_idx_null)() );
554 :
555 12039 : FD_COMPILER_MFENCE();
556 12039 : FD_VOLATILE( slist->magic ) = SLIST_MAGIC;
557 12039 : FD_COMPILER_MFENCE();
558 :
559 12039 : return shmem;
560 12042 : }
561 :
562 : SLIST_IMPL_STATIC SLIST_(t) *
563 12048 : SLIST_(join)( void * shslist ) {
564 12048 : SLIST_(private_t) * slist = (SLIST_(private_t) *)shslist;
565 :
566 12048 : if( FD_UNLIKELY( !slist ) ) {
567 3 : FD_LOG_WARNING(( "NULL shslist" ));
568 3 : return NULL;
569 3 : }
570 :
571 12045 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)slist, SLIST_(align)() ) ) ) {
572 3 : FD_LOG_WARNING(( "misaligned shslist" ));
573 3 : return NULL;
574 3 : }
575 :
576 12042 : if( FD_UNLIKELY( slist->magic!=SLIST_MAGIC ) ) {
577 3 : FD_LOG_WARNING(( "bad magic" ));
578 3 : return NULL;
579 3 : }
580 :
581 12039 : return (SLIST_(t) *)slist;
582 12042 : }
583 :
584 : SLIST_IMPL_STATIC void *
585 12039 : SLIST_(leave)( SLIST_(t) * join ) {
586 :
587 12039 : if( FD_UNLIKELY( !join ) ) {
588 3 : FD_LOG_WARNING(( "NULL join" ));
589 3 : return NULL;
590 3 : }
591 :
592 12036 : return (void *)join;
593 12039 : }
594 :
595 : SLIST_IMPL_STATIC void *
596 12045 : SLIST_(delete)( void * shslist ) {
597 12045 : SLIST_(private_t) * slist = (SLIST_(private_t) *)shslist;
598 :
599 12045 : if( FD_UNLIKELY( !slist ) ) {
600 3 : FD_LOG_WARNING(( "NULL shslist" ));
601 3 : return NULL;
602 3 : }
603 :
604 12042 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)slist, SLIST_(align)() ) ) ) {
605 3 : FD_LOG_WARNING(( "misaligned shslist" ));
606 3 : return NULL;
607 3 : }
608 :
609 12039 : if( FD_UNLIKELY( slist->magic!=SLIST_MAGIC ) ) {
610 3 : FD_LOG_WARNING(( "bad magic" ));
611 3 : return NULL;
612 3 : }
613 :
614 12036 : FD_COMPILER_MFENCE();
615 12036 : FD_VOLATILE( slist->magic ) = 0UL;
616 12036 : FD_COMPILER_MFENCE();
617 :
618 12036 : return shslist;
619 12039 : }
620 :
621 : SLIST_IMPL_STATIC int
622 : SLIST_(verify)( SLIST_(t) const * join,
623 : ulong ele_cnt,
624 187540263 : SLIST_ELE_T const * pool ) {
625 :
626 3750757227 : # define SLIST_TEST(c) do { \
627 3750757227 : if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return -1; } \
628 3750757227 : } while(0)
629 :
630 : /* Validate input args */
631 :
632 187540263 : SLIST_TEST( join );
633 187540263 : SLIST_TEST( ele_cnt<=SLIST_(ele_max)() );
634 187540263 : SLIST_TEST( (!!pool) | (!ele_cnt) );
635 :
636 : /* Iterate forward through the slist, validating as we go */
637 :
638 187540263 : SLIST_(private_t) const * slist = SLIST_(private_const)( join );
639 :
640 187540263 : SLIST_TEST( slist->magic==SLIST_MAGIC );
641 :
642 187540263 : ulong rem = ele_cnt;
643 187540263 : ulong prev_idx = SLIST_(private_idx_null)();
644 187540263 : ulong ele_idx = SLIST_(private_idx)( slist->head );
645 1594068219 : while( !SLIST_(private_idx_is_null)( ele_idx ) ) {
646 :
647 : /* Visit ele_idx */
648 :
649 1406527956 : SLIST_TEST( rem ); rem--; /* Test for cycles */
650 1406527956 : SLIST_TEST( ele_idx<ele_cnt ); /* Test valid ele_idx */
651 :
652 : /* Advance to next element */
653 :
654 1406527956 : prev_idx = ele_idx;
655 1406527956 : ele_idx = SLIST_(private_idx)( pool[ ele_idx ].SLIST_NEXT );
656 1406527956 : }
657 :
658 187540263 : SLIST_TEST( SLIST_(private_idx)( slist->tail )==prev_idx );
659 :
660 187540263 : # undef SLIST_TEST
661 :
662 187540263 : return 0;
663 187540263 : }
664 :
665 : FD_PROTOTYPES_END
666 :
667 : #undef SLIST_IMPL_STATIC
668 :
669 : #endif
670 :
671 : #undef SLIST_
672 :
673 : #undef SLIST_IMPL_STYLE
674 : #undef SLIST_MAGIC
675 : #undef SLIST_NEXT
676 : #undef SLIST_IDX_T
677 : #undef SLIST_ELE_T
678 : #undef SLIST_NAME
|