The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Functions
atomic_queue.c File Reference

Thread-safe queues. More...

#include <stdint.h>
#include <stdalign.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <freeradius-devel/autoconf.h>
#include <freeradius-devel/io/atomic_queue.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/util/math.h>
#include <freeradius-devel/util/strerror.h>
#include <freeradius-devel/util/syserror.h>
+ Include dependency graph for atomic_queue.c:

Go to the source code of this file.

Data Structures

struct  fr_atomic_queue_owner_t
 Owner handle for a queue outside the talloc hierarchy. More...
 
struct  fr_atomic_queue_s
 Structure to hold the atomic queue. More...
 
struct  fr_atomic_queue_slot_t
 One slot in the queue. More...
 
struct  fr_atomic_ring_s
 
struct  fr_atomic_ring_segment_s
 

Macros

#define acquire(_var)   atomic_load_explicit(&_var, memory_order_acquire)
 
#define atomic_int64_t   _Atomic(int64_t)
 
#define atomic_uint32_t   _Atomic(uint32_t)
 
#define atomic_uint64_t   _Atomic(uint64_t)
 
#define CACHE_LINE_SIZE   128
 
#define cas_decr(_store, _var)   atomic_compare_exchange_strong_explicit(&_store, &_var, _var - 1, memory_order_release, memory_order_relaxed)
 
#define cas_incr(_store, _var)   atomic_compare_exchange_strong_explicit(&_store, &_var, _var + 1, memory_order_release, memory_order_relaxed)
 
#define load(_var)   atomic_load_explicit(&_var, memory_order_relaxed)
 
#define store(_store, _var)   atomic_store_explicit(&_store, _var, memory_order_release)
 

Typedefs

typedef struct fr_atomic_ring_segment_s fr_atomic_ring_segment_t
 

Functions

static int _atomic_queue_owner_free (fr_atomic_queue_owner_t *owner)
 
static int _atomic_ring_free (fr_atomic_ring_t *ring)
 talloc destructor for fr_atomic_ring_t: walk the chain and free segments
 
static size_t atomic_queue_bytes (size_t num, size_t stripes)
 Bytes needed for a queue of num slots, header included.
 
static void atomic_queue_init (fr_atomic_queue_t *aq, size_t num, size_t elem_len)
 Initialise the sequence numbers and head/tail on a fresh queue buffer.
 
static fr_atomic_queue_t * atomic_queue_malloc_raw (size_t num, size_t elem_len)
 Create fixed-size atomic queue outside any talloc hierarchy.
 
static size_t atomic_queue_num_lines (size_t num, size_t stripes)
 Number of cache lines needed to hold num slots.
 
static int atomic_queue_shm_open (size_t len)
 Open an anonymous shared memory object of a given length.
 
static fr_atomic_queue_slot_t * atomic_queue_slot (fr_atomic_queue_t *aq, int64_t pos)
 Map a queue position to its slot.
 
static size_t atomic_queue_stripes (size_t elem_len)
 How many slots a line holds for an element size.
 
static fr_atomic_ring_segment_t * atomic_ring_segment_alloc (size_t seg_size)
 Allocate a fresh segment and its embedded queue.
 
static void atomic_ring_segment_free (fr_atomic_ring_segment_t *s)
 
static void atomic_ring_segment_publish (fr_atomic_ring_t *ring, fr_atomic_ring_segment_t *h, fr_atomic_ring_segment_t *n)
 Link a new segment after the current head and make it the head.
 
void fr_atomic_queue_debug (FILE *fp, fr_atomic_queue_t *aq)
 Dump an atomic queue.
 
void fr_atomic_queue_free (fr_atomic_queue_t **aq)
 Free an atomic queue if it's not freed by ctx.
 
fr_atomic_queue_t * fr_atomic_queue_malloc (TALLOC_CTX *ctx, size_t num, size_t elem_len)
 Create fixed-size atomic queue outside the talloc hierarchy, owned by a talloc context.
 
fr_atomic_queue_t * fr_atomic_queue_mmap (TALLOC_CTX *ctx, int *fd, size_t num, size_t elem_len)
 Create or attach to a fixed-size atomic queue in shared memory, owned by a talloc context.
 
bool fr_atomic_queue_mpmc_pop (fr_atomic_queue_t *aq, void *data)
 Copy an element out of the atomic queue, any number of consumers.
 
bool fr_atomic_queue_mpmc_push (fr_atomic_queue_t *aq, void const *data)
 Copy an element into the atomic queue, any number of producers.
 
size_t fr_atomic_queue_size (fr_atomic_queue_t *aq)
 
bool fr_atomic_queue_spsc_pop (fr_atomic_queue_t *aq, void *data)
 Copy an element out of the atomic queue, one consumer only.
 
bool fr_atomic_queue_spsc_push (fr_atomic_queue_t *aq, void const *data)
 Copy an element into the atomic queue, one producer only.
 
fr_atomic_queue_t * fr_atomic_queue_talloc (TALLOC_CTX *ctx, size_t num, size_t elem_len)
 Create a fixed-size atomic queue.
 
fr_atomic_ring_t * fr_atomic_ring_alloc (TALLOC_CTX *ctx, size_t seg_size)
 Allocate an empty SPSC ring.
 
void fr_atomic_ring_free (fr_atomic_ring_t **ring_p)
 Free the ring and all remaining segments.
 
bool fr_atomic_ring_pop (fr_atomic_ring_t *ring, void **p_data)
 Pop a pointer from the ring, advancing past drained segments.
 
bool fr_atomic_ring_push (fr_atomic_ring_t *ring, void *data)
 Push a pointer into the ring; allocate a new segment on overflow.
 

Detailed Description

Thread-safe queues.

Id
274dcdfe7595fbb61bd6e651dd7e2a1212048fe1

This is an implementation of a bounded MPMC ring buffer with per-slot sequence numbers, as described by Dmitry Vyukov, and independently discovered/implemented by Alister Winfield.

Definition in file atomic_queue.c.


Data Structure Documentation

◆ fr_atomic_queue_owner_t

struct fr_atomic_queue_owner_t

Owner handle for a queue outside the talloc hierarchy.

Raw and mapped queues keep their memory outside talloc. This handle is the only talloc'd part, so freeing the context the handle lives in releases the queue.

Definition at line 382 of file atomic_queue.c.

+ Collaboration diagram for fr_atomic_queue_owner_t:
Data Fields
fr_atomic_queue_t * aq The memory to release.
int fd The shared memory object behind a mapping, or -1 for a raw allocation.
size_t len Length of a mapping.

◆ fr_atomic_queue_s

struct fr_atomic_queue_s

Structure to hold the atomic queue.

Note
DO NOT redorder these fields without understanding how alignas works and maintaining separation. The head and tail must be in different cache lines to reduce contention between producers and consumers. Cold data (num, chunk) can share a cache line, but must be separated from head, tail and the line array.

Definition at line 138 of file atomic_queue.c.

Data Fields
void * chunk The start of the talloc chunk to pass to free, or NULL if this queue was allocated raw via fr_atomic_queue_malloc.

We need to play tricks to get aligned memory with talloc.

size_t elem_len Size of one element.
atomic_int64_t head Position of the producer.

Cache aligned bytes to ensure it's in a different cache line to tail to reduce memory contention.

size_t line_mask Low bits of a slot index give its line: line[slot & line_mask].

Set at init to num_lines - 1.

uint8_t line_shift High bits of a slot index give its stripe within that line: .stripe[slot >> line_shift].

Equal to log2(num_lines). Set at init, so a lookup is a mask and a shift, no division and no modulo!

uint8_t lines[] The lines, each exactly one cache line, aligned with cache lines to ensure producers and consumers don't conflict.
size_t num Elements the queue holds.

This is static. Also needs to be cache aligned, otherwise it can end up directly after tail in memory and share a cache line.

size_t slot_len The line divided by the stripes: header, element, padding.
size_t stripes Slots per line.

The largest power of two the element allows.

atomic_int64_t tail Position of the consumer.

Cache aligned bytes to ensure it's in a different cache line to tail to reduce memory contention. Reads may still need to occur from num whilst the producer is writing to tail.

◆ fr_atomic_queue_slot_t

struct fr_atomic_queue_slot_t

One slot in the queue.

The sequence number, then the element: elem_len of data, padded out to the slot size. For the pointer API the element is the pointer itself.

Must not be packed. Packing drops the struct's alignment to 1 (same as an array of uint8_t), so the compiler has to treat seq as possibly unaligned. The native atomic instructions require an aligned address, so clang stops emitting them and calls the libatomic fallback instead, which takes a mutex. That turns every push and pop on this lock free queue into a locked operation. gcc emits the native instruction regardless, and relies on the address being aligned at runtime.

Definition at line 89 of file atomic_queue.c.

Data Fields
uint8_t data[] The element, 8 byte aligned as slots are a power of two bytes from a line boundary.
atomic_int64_t seq The position this slot was last written or freed at.

◆ fr_atomic_ring_s

struct fr_atomic_ring_s

Definition at line 839 of file atomic_queue.c.

Data Fields
size_t seg_size Capacity of each segment.

◆ fr_atomic_ring_segment_s

struct fr_atomic_ring_segment_s

Definition at line 832 of file atomic_queue.c.

+ Collaboration diagram for fr_atomic_ring_segment_s:
Data Fields
fr_atomic_queue_t * q Per-segment queue, driven with the spsc functions.

Macro Definition Documentation

◆ acquire

#define acquire (   _var)    atomic_load_explicit(&_var, memory_order_acquire)

Definition at line 60 of file atomic_queue.c.

◆ atomic_int64_t

#define atomic_int64_t   _Atomic(int64_t)

Definition at line 53 of file atomic_queue.c.

◆ atomic_uint32_t

#define atomic_uint32_t   _Atomic(uint32_t)

Definition at line 54 of file atomic_queue.c.

◆ atomic_uint64_t

#define atomic_uint64_t   _Atomic(uint64_t)

Definition at line 55 of file atomic_queue.c.

◆ CACHE_LINE_SIZE

#define CACHE_LINE_SIZE   128

Definition at line 72 of file atomic_queue.c.

◆ cas_decr

#define cas_decr (   _store,
  _var 
)    atomic_compare_exchange_strong_explicit(&_store, &_var, _var - 1, memory_order_release, memory_order_relaxed)

Definition at line 58 of file atomic_queue.c.

◆ cas_incr

#define cas_incr (   _store,
  _var 
)    atomic_compare_exchange_strong_explicit(&_store, &_var, _var + 1, memory_order_release, memory_order_relaxed)

Definition at line 57 of file atomic_queue.c.

◆ load

#define load (   _var)    atomic_load_explicit(&_var, memory_order_relaxed)

Definition at line 59 of file atomic_queue.c.

◆ store

#define store (   _store,
  _var 
)    atomic_store_explicit(&_store, _var, memory_order_release)

Definition at line 61 of file atomic_queue.c.

Typedef Documentation

◆ fr_atomic_ring_segment_t

Definition at line 830 of file atomic_queue.c.

Function Documentation

◆ _atomic_queue_owner_free()

static int _atomic_queue_owner_free ( fr_atomic_queue_owner_t *  owner)
static

Definition at line 389 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _atomic_ring_free()

static int _atomic_ring_free ( fr_atomic_ring_t *  ring)
static

talloc destructor for fr_atomic_ring_t: walk the chain and free segments

Definition at line 876 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_queue_bytes()

static size_t atomic_queue_bytes ( size_t  num,
size_t  stripes 
)
inlinestatic

Bytes needed for a queue of num slots, header included.

Parameters
[in]numSlot count, already rounded up to a power of 2.

Definition at line 223 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_queue_init()

static void atomic_queue_init ( fr_atomic_queue_t *  aq,
size_t  num,
size_t  elem_len 
)
static

Initialise the sequence numbers and head/tail on a fresh queue buffer.

Shared between the talloc and raw allocators. The buffer must already be cache-line aligned and sized to hold num slots.

Parameters
[in]aqThe queue buffer to initialise.
[in]numSlot count, already rounded up to a power of 2.
[in]elem_lenSize of one element, known to fit.

Definition at line 254 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_queue_malloc_raw()

static fr_atomic_queue_t * atomic_queue_malloc_raw ( size_t  num,
size_t  elem_len 
)
static

Create fixed-size atomic queue outside any talloc hierarchy.

Backed by posix_memalign. The queue has no owner: chunk is NULL and the caller releases it with fr_atomic_queue_free or plain free().

For callers that allocate from threads where talloc is not safe (for example, library-owned callback threads).

Parameters
[in]numThe number of entries in the queue.
[in]elem_lenThe size of one element.
Returns
  • NULL on error.
  • fr_atomic_queue_t *, a pointer to the allocated and initialized queue.

Definition at line 357 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_queue_num_lines()

static size_t atomic_queue_num_lines ( size_t  num,
size_t  stripes 
)
inlinestatic

Number of cache lines needed to hold num slots.

A queue smaller than one line uses a single, partly filled line.

Parameters
[in]numSlot count, already rounded up to a power of 2.

Definition at line 212 of file atomic_queue.c.

+ Here is the caller graph for this function:

◆ atomic_queue_shm_open()

static int atomic_queue_shm_open ( size_t  len)
static

Open an anonymous shared memory object of a given length.

Parameters
[in]lenbytes the object must hold.
Returns
  • The descriptor, close on exec.
  • -1 on error, with the error in fr_strerror.

Definition at line 445 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_queue_slot()

static fr_atomic_queue_slot_t * atomic_queue_slot ( fr_atomic_queue_t *  aq,
int64_t  pos 
)
inlinestatic

Map a queue position to its slot.

Positions wrap at num. Within one stripe, consecutive positions increment one line at a time, and move to the next stripe once every line has been visited.

Parameters
[in]aqThe queue.
[in]posThe head or tail position, unmasked.

Definition at line 237 of file atomic_queue.c.

+ Here is the caller graph for this function:

◆ atomic_queue_stripes()

static size_t atomic_queue_stripes ( size_t  elem_len)
inlinestatic

How many slots a line holds for an element size.

The largest power of two such that the line divided by it still holds the slot header and the element. A power of two keeps the slot size a power of two and the line count a power of two, which the mask and shift lookup depends on.

Parameters
[in]elem_lenSize of the element.
Returns
0 if the element does not fit in a line with its header.

Definition at line 193 of file atomic_queue.c.

+ Here is the caller graph for this function:

◆ atomic_ring_segment_alloc()

static fr_atomic_ring_segment_t * atomic_ring_segment_alloc ( size_t  seg_size)
static

Allocate a fresh segment and its embedded queue.

Uses the raw (non-talloc) allocator so this function is safe to call from the producer thread even when that thread cannot safely use talloc.

Definition at line 852 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_ring_segment_free()

static void atomic_ring_segment_free ( fr_atomic_ring_segment_t *  s)
static

Definition at line 869 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ atomic_ring_segment_publish()

static void atomic_ring_segment_publish ( fr_atomic_ring_t *  ring,
fr_atomic_ring_segment_t *  h,
fr_atomic_ring_segment_t *  n 
)
inlinestatic

Link a new segment after the current head and make it the head.

The consumer only inspects h->next and advances past h once it sees a non-NULL value there, so h->next is published with release ordering, which pairs with the acquire in fr_atomic_ring_pop().

Modelled for Coverity in src/coverity-model/merged_model.c, as the analyser does not treat an atomic store as publishing the pointer.

Parameters
[in]ringthe segment belongs to.
[in]hCurrent head segment.
[in]nNew segment to publish.

Definition at line 950 of file atomic_queue.c.

+ Here is the caller graph for this function:

◆ fr_atomic_queue_debug()

void fr_atomic_queue_debug ( FILE *  fp,
fr_atomic_queue_t *  aq 
)

Dump an atomic queue.

Absolutely NOT thread-safe.

Parameters
[in]aqThe atomic queue to debug.
[in]fpwhere the debugging information will be printed.

Definition at line 1061 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_free()

void fr_atomic_queue_free ( fr_atomic_queue_t **  aq)

Free an atomic queue if it's not freed by ctx.

The queue memory must be cache line aligned, so it lives in one of three places: a talloc aligned array (chunk is the array), a raw allocation owned by a talloc handle (chunk is the handle, whose destructor frees the queue), or a raw allocation with no owner (chunk is NULL).

Definition at line 557 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_malloc()

fr_atomic_queue_t * fr_atomic_queue_malloc ( TALLOC_CTX *  ctx,
size_t  num,
size_t  elem_len 
)

Create fixed-size atomic queue outside the talloc hierarchy, owned by a talloc context.

The queue itself is a raw posix_memalign allocation, so it can be pushed to and popped from by threads where talloc is not safe, and can later be placed in memory talloc does not manage. A small owner handle allocated in ctx frees the queue when ctx is freed, or when the caller calls fr_atomic_queue_free.

Parameters
[in]ctxThe talloc ctx which owns the queue.
[in]numThe number of entries in the queue.
[in]elem_lenThe size of one element.
Returns
  • NULL on error.
  • fr_atomic_queue_t *, a pointer to the allocated and initialized queue.

Definition at line 416 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_mmap()

fr_atomic_queue_t * fr_atomic_queue_mmap ( TALLOC_CTX *  ctx,
int *  fd,
size_t  num,
size_t  elem_len 
)

Create or attach to a fixed-size atomic queue in shared memory, owned by a talloc context.

With *fd negative, a new anonymous shared memory object is created, the queue initialised in it, and its descriptor written back for the caller to pass to another process. With a descriptor, that object is mapped and must already hold a queue of this size; the mapping is not reinitialised. Either way the handle owns the descriptor and closes it with the mapping. Pages are aligned well beyond a cache line.

Parameters
[in]ctxThe talloc ctx which owns the queue.
[in,out]fdA shared memory object holding a queue to attach to, or -1 to create one, in which case the new descriptor is written here.
[in]numThe number of entries in the queue.
[in]elem_lenThe size of one element.
Returns
  • NULL on error, with the error in fr_strerror.
  • fr_atomic_queue_t *, a pointer to the mapped queue.

Definition at line 482 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_mpmc_pop()

bool fr_atomic_queue_mpmc_pop ( fr_atomic_queue_t *  aq,
void *  data 
)

Copy an element out of the atomic queue, any number of consumers.

For a queue of pointers, data is the address of a pointer to fill.

Parameters
[in]aqthe atomic queue to retrieve data from.
[out]datawhere to write the element, elem_len long.
Returns
  • true on successful pop
  • false on queue empty

Definition at line 701 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_mpmc_push()

bool fr_atomic_queue_mpmc_push ( fr_atomic_queue_t *  aq,
void const *  data 
)

Copy an element into the atomic queue, any number of producers.

For a queue of pointers, data is the address of the pointer.

Parameters
[in]aqThe atomic queue to add data to.
[in]datathe element, elem_len long.
Returns
  • true on successful push
  • false on queue full

Definition at line 579 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_size()

size_t fr_atomic_queue_size ( fr_atomic_queue_t *  aq)

Definition at line 813 of file atomic_queue.c.

+ Here is the caller graph for this function:

◆ fr_atomic_queue_spsc_pop()

bool fr_atomic_queue_spsc_pop ( fr_atomic_queue_t *  aq,
void *  data 
)

Copy an element out of the atomic queue, one consumer only.

With one consumer nobody else advances tail, so no compare-and-swap: the slot is full when its sequence number is one past tail.

Parameters
[in]aqthe atomic queue to retrieve data from.
[out]datawhere to write the element, elem_len long.
Returns
  • true on successful pop
  • false on queue empty

Definition at line 799 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_spsc_push()

bool fr_atomic_queue_spsc_push ( fr_atomic_queue_t *  aq,
void const *  data 
)

Copy an element into the atomic queue, one producer only.

The same slots and sequence numbers as the mpmc functions, so the consumer may be either flavour. With one producer nobody else advances head, so there is nothing to race and no compare-and-swap: the slot is free when its sequence number equals head.

Parameters
[in]aqThe atomic queue to add data to.
[in]datathe element, elem_len long.
Returns
  • true on successful push
  • false on queue full

Definition at line 774 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_queue_talloc()

fr_atomic_queue_t * fr_atomic_queue_talloc ( TALLOC_CTX *  ctx,
size_t  num,
size_t  elem_len 
)

Create a fixed-size atomic queue.

Push and pop copy elem_len bytes in and out, so a queue of pointers is a queue of sizeof(uintptr_t) elements whose callers pass the address of the pointer. Nothing is allocated per element, and nothing has to be freed by the consumer.

Note
the queue must be freed explicitly by the ctx being freed, or by using the fr_atomic_queue_free function.
Parameters
[in]ctxThe talloc ctx to allocate the queue in.
[in]numThe number of entries in the queue.
[in]elem_lenThe size of one element. Elements are 8 byte aligned.
Returns
  • NULL on error, including an element which does not fit in a cache line.
  • fr_atomic_queue_t *, a pointer to the allocated and initialized queue.

Definition at line 310 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_ring_alloc()

fr_atomic_ring_t * fr_atomic_ring_alloc ( TALLOC_CTX *  ctx,
size_t  seg_size 
)

Allocate an empty SPSC ring.

Parameters
[in]ctxtalloc ctx that owns the ring handle (segments live outside talloc; they are freed by the ring's destructor).
[in]seg_sizePer-segment capacity. Rounded up to a power of 2.
Returns
  • NULL on error.
  • A ring containing one initial (empty) segment.

Definition at line 900 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_ring_free()

void fr_atomic_ring_free ( fr_atomic_ring_t **  ring_p)

Free the ring and all remaining segments.

Equivalent to talloc_free() on the ring, but nulls the caller's handle in the style of fr_atomic_queue_free.

Definition at line 929 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_ring_pop()

bool fr_atomic_ring_pop ( fr_atomic_ring_t *  ring,
void **  p_data 
)

Pop a pointer from the ring, advancing past drained segments.

Single-consumer only. Must not be called concurrently with itself.

Parameters
[in]ringRing to pop from.
[out]p_dataWhere to write the popped value on success.
Returns
  • true if a value was popped.
  • false if the ring is currently empty.

Definition at line 995 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fr_atomic_ring_push()

bool fr_atomic_ring_push ( fr_atomic_ring_t *  ring,
void *  data 
)

Push a pointer into the ring; allocate a new segment on overflow.

Single-producer only. Must not be called concurrently with itself.

Parameters
[in]ringRing to push into.
[in]dataValue to push (must be non-NULL).
Returns
  • true on success.
  • false if both the current segment is full and a new segment could not be allocated.

Definition at line 968 of file atomic_queue.c.

+ Here is the call graph for this function:
+ Here is the caller graph for this function: