Line data Source code
1 : #ifndef HEADER_fd_src_disco_events_fd_circq_h 2 : #define HEADER_fd_src_disco_events_fd_circq_h 3 : 4 : /* The circular buffer is a structure, which stores a queue of messages, 5 : supporting two operations: push_back and pop_front. Unlike a regular 6 : queue, the circular buffer is fixed size and push_back must always 7 : succeed. 8 : 9 : To ensure push_back always succeeds, the circular buffer will evict 10 : old messages if necessary to make room for the new one. 11 : 12 : One more complication is that the circular buffer must store 13 : metadata about the messages in the data buffer itself, as it does not 14 : have a separate metadata region. The structure of the buffer then 15 : looks as follows: 16 : 17 : +-------+-----+------+-----+-------+-----+------+-----+-------+-----+------+ 18 : + meta0 | pad | msg0 | pad | meta1 | pad | msg1 | pad | meta2 | pad | msg2 | 19 : +-------+-----+------+-----+-------+-----+------+-----+-------+-----+------+ 20 : ^ | ^ | ^ | 21 : | +-----next---------next--+ +------------------------+ | 22 : | | 23 : head tail 24 : 25 : Here, the meta elements are fd_circq_message_t, which each point to 26 : the next message in the queue, and head, tail are the head and tail 27 : of the queue respectively. */ 28 : 29 : #include "../fd_disco_base.h" 30 : 31 0 : #define FD_CIRCQ_ALIGN (4096UL) 32 : 33 : struct __attribute__((aligned(FD_CIRCQ_ALIGN))) fd_circq_private { 34 : /* Current count of elements in the queue. */ 35 : ulong cnt; 36 : 37 : /* These are offsets relative to the end of this struct of the 38 : metadata for the first, and last message in the queue, 39 : respectively. */ 40 : ulong head; 41 : ulong tail; 42 : 43 : ulong size; 44 : 45 : struct { 46 : ulong drop_cnt; 47 : } metrics; 48 : 49 : /* padding out to 4k here ... */ 50 : }; 51 : 52 : typedef struct fd_circq_private fd_circq_t; 53 : 54 : FD_PROTOTYPES_BEGIN 55 : 56 : FD_FN_CONST ulong 57 : fd_circq_align( void ); 58 : 59 : FD_FN_CONST ulong 60 : fd_circq_footprint( ulong sz ); 61 : 62 : void * 63 : fd_circq_new( void * shmem, 64 : ulong sz ); 65 : 66 : fd_circq_t * 67 : fd_circq_join( void * shbuf ); 68 : 69 : void * 70 : fd_circq_leave( fd_circq_t * buf ); 71 : 72 : void * 73 : fd_circq_delete( void * shbuf ); 74 : 75 : /* fd_circq_push_back appends a message of size sz into the circular 76 : buffer, evicting any old messages if they would be overwritten when 77 : the buffer wraps around. Returns the address of the memory contents 78 : in the buffer on success, or NULL on failure. The only two reasons 79 : for failure are if the requested sz (along with the message metadata) 80 : exceeds the size of the entire buffer and can't fit, or if the 81 : requested alignment is not a power of 2, or is larger than 4096. */ 82 : 83 : uchar * 84 : fd_circq_push_back( fd_circq_t * circq, 85 : ulong align, 86 : ulong footprint ); 87 : 88 : /* fd_circq_pop_front pops the oldest message from the circular buffer 89 : and returns the address of the memory contents in the buffer. The 90 : memory contents are guaranteed to be valid until the next call to 91 : fd_circq_push_back. Returns NULL if there are no messages in the 92 : circular buffer. */ 93 : 94 : uchar const * 95 : fd_circq_pop_front( fd_circq_t * circq ); 96 : 97 : FD_PROTOTYPES_END 98 : 99 : #endif /* HEADER_fd_src_disco_events_fd_circq_h */