21RCSID(
"$Id: bc358232c9a3e386653997a0745909b1a084cd60 $")
23#include <freeradius-devel/io/atomic_queue.h>
24#include <freeradius-devel/util/debug.h>
40#define TEST(_name) do { printf(" %-48s ", _name); fflush(stdout); } while (0)
41#define OK() do { printf("ok\n"); } while (0)
42#define FAIL(fmt, ...) do { \
43 printf("FAIL\n " fmt "\n", ##__VA_ARGS__); \
44 fr_exit_now(EXIT_FAILURE); \
47#define CHECK(cond, fmt, ...) do { \
48 if (!(cond)) FAIL(fmt, ##__VA_ARGS__); \
56 TEST(
"alloc/free empty ring");
59 CHECK(ring != NULL,
"fr_atomic_ring_alloc returned NULL");
62 CHECK(ring == NULL,
"fr_atomic_ring_free did not null the handle");
73 TEST(
"push/pop within one segment preserves FIFO");
77 for (i = 1; i <= 4; i++) {
80 for (i = 1; i <= 4; i++) {
82 CHECK((intptr_t)
data == i,
"FIFO broken: expected %" PRIdPTR
", got %" PRIdPTR, i, (intptr_t)
data);
96 size_t const seg_size = 4;
97 size_t const n = seg_size * 4;
99 TEST(
"push past segment capacity grows transparently");
103 for (i = 1; i <= (intptr_t)
n; i++) {
106 for (i = 1; i <= (intptr_t)
n; i++) {
108 CHECK((intptr_t)
data == i,
"FIFO broken across segments: expected %" PRIdPTR
", got %" PRIdPTR,
121 intptr_t push_seq = 1;
122 intptr_t pop_seq = 1;
126 TEST(
"interleaved push/pop keeps FIFO across segment advances");
135 for (round = 0; round < 32; round++) {
136 int batch = (round % 5) + 6;
139 for (i = 0; i < batch; i++) {
141 "push %" PRIdPTR
" failed at round %d", push_seq, round);
144 for (i = 0; i < batch; i++) {
146 "pop %" PRIdPTR
" failed at round %d", pop_seq, round);
148 "FIFO broken at round %d: expected %" PRIdPTR
", got %" PRIdPTR,
149 round, pop_seq, (intptr_t)
data);
165 TEST(
"free releases all remaining segments");
169 for (i = 1; i <= 32; i++) {
183#define STRESS_N 200000
195 for (i = 1; i <= sa->
n; i++) {
214 errp = malloc(
sizeof(*errp));
217 while (expect <= sa->
n) {
222 if ((uintptr_t)
data != expect) {
235 pthread_t prod, cons;
241 TEST(
"producer/consumer stress - 200k items, 4-slot segments");
248 CHECK(rc == 0,
"pthread_create(consumer) failed: %s", strerror(rc));
250 CHECK(rc == 0,
"pthread_create(producer) failed: %s", strerror(rc));
252 pthread_join(prod, NULL);
253 pthread_join(cons, &cons_ret);
255 err = *(uintptr_t *)cons_ret;
257 CHECK(
err == 0,
"consumer saw out-of-order item at position %" PRIuPTR,
err);
278 fprintf(stderr,
"usage: atomic_ring_test\n");
282 printf(
"atomic_ring_test:\n");
291 printf(
" all tests passed\n");
bool fr_atomic_ring_push(fr_atomic_ring_t *ring, void *data)
Push a pointer into the ring; allocate a new segment on overflow.
void fr_atomic_ring_free(fr_atomic_ring_t **ring_p)
Free the ring and all remaining segments.
fr_atomic_ring_t * fr_atomic_ring_alloc(TALLOC_CTX *ctx, size_t seg_size)
Allocate an empty SPSC ring.
bool fr_atomic_ring_pop(fr_atomic_ring_t *ring, void **p_data)
Pop a pointer from the ring, advancing past drained segments.
static void * stress_producer(void *arg)
static void test_grow_across_segments(TALLOC_CTX *ctx)
static void test_interleaved(TALLOC_CTX *ctx)
static void test_free_nonempty(TALLOC_CTX *ctx)
static void * stress_consumer(void *arg)
int main(int argc, UNUSED char *argv[])
#define CHECK(cond, fmt,...)
static void test_alloc_free(TALLOC_CTX *ctx)
static void test_stress_two_thread(TALLOC_CTX *ctx)
static void test_push_pop_single_segment(TALLOC_CTX *ctx)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
static TALLOC_CTX * autofree
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.