mirror of https://github.com/OISF/suricata
Merge 3be820bfbf into 9a37bb659b
commit
59de7a2a86
@ -0,0 +1,355 @@
|
|||||||
|
/* Copyright (C) 2026 Open Information Security Foundation
|
||||||
|
*
|
||||||
|
* You can copy, redistribute or modify this Program under the terms of
|
||||||
|
* the GNU General Public License version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* version 2 along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "suricata-common.h"
|
||||||
|
#include "util-ring-buffer.h"
|
||||||
|
#include "util-unittest.h"
|
||||||
|
|
||||||
|
// Bit-mask to wrap the index around the ring buffer capacity (power of 2)
|
||||||
|
#define SCRINGBUFFER_ADVANCE(index, count, capacity) (((index) + (count)) & ((capacity)-1))
|
||||||
|
|
||||||
|
struct SCRingBuffer_ {
|
||||||
|
uint8_t *data;
|
||||||
|
size_t element_size;
|
||||||
|
uint32_t capacity;
|
||||||
|
uint32_t head;
|
||||||
|
uint32_t tail;
|
||||||
|
uint32_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
SCRingBuffer *SCRingBufferInit(uint32_t capacity, size_t element_size)
|
||||||
|
{
|
||||||
|
if (capacity == 0 || (capacity & (capacity - 1)) != 0 || element_size == 0 ||
|
||||||
|
element_size > SIZE_MAX / capacity) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SCRingBuffer *rb = SCCalloc(1, sizeof(*rb));
|
||||||
|
if (rb == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rb->data = SCMalloc(capacity * element_size);
|
||||||
|
if (rb->data == NULL) {
|
||||||
|
SCFree(rb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
rb->capacity = capacity;
|
||||||
|
rb->element_size = element_size;
|
||||||
|
return rb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SCRingBufferFree(SCRingBuffer *rb)
|
||||||
|
{
|
||||||
|
if (rb != NULL) {
|
||||||
|
SCFree(rb->data);
|
||||||
|
SCFree(rb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SCRingBufferCount(const SCRingBuffer *rb)
|
||||||
|
{
|
||||||
|
return rb == NULL ? 0 : rb->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SCRingBufferSpace(const SCRingBuffer *rb)
|
||||||
|
{
|
||||||
|
return rb == NULL ? 0 : rb->capacity - rb->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SCRingBufferEnqueue(SCRingBuffer *rb, const void *items, uint32_t count)
|
||||||
|
{
|
||||||
|
if (rb == NULL || count > (rb->capacity - rb->count) || (count > 0 && items == NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint32_t first_chunk_count = MIN(count, rb->capacity - rb->tail);
|
||||||
|
size_t first_chunk_size = first_chunk_count * rb->element_size;
|
||||||
|
memcpy(rb->data + rb->tail * rb->element_size, items, first_chunk_size);
|
||||||
|
if (first_chunk_count < count) {
|
||||||
|
memcpy(rb->data, (const uint8_t *)items + first_chunk_size,
|
||||||
|
(count - first_chunk_count) * rb->element_size);
|
||||||
|
}
|
||||||
|
rb->tail = SCRINGBUFFER_ADVANCE(rb->tail, count, rb->capacity);
|
||||||
|
rb->count += count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SCRingBufferDequeue(SCRingBuffer *rb, void *items, uint32_t count)
|
||||||
|
{
|
||||||
|
if (rb == NULL || count > rb->count || (count > 0 && items == NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint32_t first_chunk_count = MIN(count, rb->capacity - rb->head);
|
||||||
|
size_t first_chunk_size = first_chunk_count * rb->element_size;
|
||||||
|
memcpy(items, rb->data + rb->head * rb->element_size, first_chunk_size);
|
||||||
|
if (first_chunk_count < count) {
|
||||||
|
memcpy((uint8_t *)items + first_chunk_size, rb->data,
|
||||||
|
(count - first_chunk_count) * rb->element_size);
|
||||||
|
}
|
||||||
|
rb->head = SCRINGBUFFER_ADVANCE(rb->head, count, rb->capacity);
|
||||||
|
rb->count -= count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *SCRingBufferEnqueueSpanGet(SCRingBuffer *rb, uint32_t *count)
|
||||||
|
{
|
||||||
|
*count = 0;
|
||||||
|
if (rb == NULL || rb->count == rb->capacity) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*count = MIN(rb->capacity - rb->count, rb->capacity - rb->tail);
|
||||||
|
return rb->data + rb->tail * rb->element_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SCRingBufferEnqueueSpanCommit(SCRingBuffer *rb, uint32_t count)
|
||||||
|
{
|
||||||
|
if (rb == NULL || count > MIN(rb->capacity - rb->count, rb->capacity - rb->tail)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rb->tail = SCRINGBUFFER_ADVANCE(rb->tail, count, rb->capacity);
|
||||||
|
rb->count += count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef UNITTESTS
|
||||||
|
static int SCRingBufferTestInitialization(void)
|
||||||
|
{
|
||||||
|
FAIL_IF_NOT_NULL(SCRingBufferInit(0, sizeof(uint32_t)));
|
||||||
|
FAIL_IF_NOT_NULL(SCRingBufferInit(3, sizeof(uint32_t)));
|
||||||
|
FAIL_IF_NOT_NULL(SCRingBufferInit(4, 0));
|
||||||
|
FAIL_IF_NOT_NULL(SCRingBufferInit(2, SIZE_MAX / 2 + 1));
|
||||||
|
FAIL_IF(SCRingBufferCount(NULL) != 0);
|
||||||
|
FAIL_IF(SCRingBufferSpace(NULL) != 0);
|
||||||
|
SCRingBufferFree(NULL);
|
||||||
|
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(8, sizeof(uint32_t));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 0);
|
||||||
|
FAIL_IF(SCRingBufferSpace(rb) != 8);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestFullCapacity(void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
uint8_t bytes[3];
|
||||||
|
} input[] = { { { 1, 2, 3 } }, { { 4, 5, 6 } }, { { 7, 8, 9 } }, { { 10, 11, 12 } } };
|
||||||
|
uint8_t output[sizeof(input)] = { 0 };
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(4, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 4));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 4 || SCRingBufferSpace(rb) != 0);
|
||||||
|
FAIL_IF(SCRingBufferEnqueue(rb, input, 1));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 4));
|
||||||
|
FAIL_IF(memcmp(input, output, sizeof(input)) != 0);
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 0 || SCRingBufferSpace(rb) != 4);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
|
||||||
|
rb = SCRingBufferInit(1, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 1));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 1 || SCRingBufferSpace(rb) != 0);
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 1));
|
||||||
|
FAIL_IF(memcmp(input, output, sizeof(input[0])) != 0);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestWrapFifo(void)
|
||||||
|
{
|
||||||
|
const uint32_t input[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
|
||||||
|
uint32_t output[8];
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(8, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 6));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 5));
|
||||||
|
FAIL_IF(memcmp(output, input, 5 * sizeof(input[0])) != 0);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input + 6, 7));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 8 || SCRingBufferSpace(rb) != 0);
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 8));
|
||||||
|
FAIL_IF(memcmp(output, input + 5, sizeof(output)) != 0);
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 0 || SCRingBufferSpace(rb) != 8);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestRejectedTransfers(void)
|
||||||
|
{
|
||||||
|
const uint32_t input[] = { 1, 2, 3, 4, 5 };
|
||||||
|
const uint32_t sentinel[] = { 99, 99, 99, 99 };
|
||||||
|
uint32_t output[4];
|
||||||
|
memcpy(output, sentinel, sizeof(output));
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(4, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 3));
|
||||||
|
FAIL_IF(SCRingBufferEnqueue(rb, input + 3, 2));
|
||||||
|
FAIL_IF(SCRingBufferDequeue(rb, output, 4));
|
||||||
|
FAIL_IF(memcmp(output, sentinel, sizeof(output)) != 0);
|
||||||
|
FAIL_IF(SCRingBufferEnqueue(rb, NULL, 1));
|
||||||
|
FAIL_IF(SCRingBufferDequeue(rb, NULL, 1));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 3 || SCRingBufferSpace(rb) != 1);
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 3));
|
||||||
|
FAIL_IF(memcmp(output, input, 3 * sizeof(input[0])) != 0);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestZeroLength(void)
|
||||||
|
{
|
||||||
|
uint32_t item = 7;
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(2, sizeof(item));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, &item, 1));
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, NULL, 0));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, NULL, 0));
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 0));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 1 || SCRingBufferSpace(rb) != 1);
|
||||||
|
uint32_t output = 0;
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, &output, 1));
|
||||||
|
FAIL_IF(output != item);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestWriteSpan(void)
|
||||||
|
{
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(4, sizeof(uint32_t));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
uint32_t count = 0;
|
||||||
|
uint32_t *span = SCRingBufferEnqueueSpanGet(rb, &count);
|
||||||
|
FAIL_IF_NULL(span);
|
||||||
|
FAIL_IF(count != 4);
|
||||||
|
span[0] = 1;
|
||||||
|
span[1] = 2;
|
||||||
|
span[2] = 3;
|
||||||
|
uint32_t output[4] = { 99, 99, 99, 99 };
|
||||||
|
FAIL_IF(SCRingBufferDequeue(rb, output, 1));
|
||||||
|
FAIL_IF(output[0] != 99);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 0));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 0);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 3));
|
||||||
|
span = SCRingBufferEnqueueSpanGet(rb, &count);
|
||||||
|
FAIL_IF_NULL(span);
|
||||||
|
FAIL_IF(count != 1);
|
||||||
|
span[0] = 4;
|
||||||
|
FAIL_IF(SCRingBufferEnqueueSpanCommit(rb, 2));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 3 || SCRingBufferSpace(rb) != 1);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 1));
|
||||||
|
FAIL_IF_NOT_NULL(SCRingBufferEnqueueSpanGet(rb, &count));
|
||||||
|
FAIL_IF(count != 0);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 0));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 3));
|
||||||
|
FAIL_IF(output[0] != 1 || output[1] != 2 || output[2] != 3);
|
||||||
|
|
||||||
|
span = SCRingBufferEnqueueSpanGet(rb, &count);
|
||||||
|
FAIL_IF_NULL(span);
|
||||||
|
FAIL_IF(count != 3);
|
||||||
|
span[0] = 5;
|
||||||
|
span[1] = 6;
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 2));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 3));
|
||||||
|
FAIL_IF(output[0] != 4 || output[1] != 5 || output[2] != 6);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestCallerOwnership(void)
|
||||||
|
{
|
||||||
|
uint32_t values[] = { 11, 22 };
|
||||||
|
uint32_t *input[] = { &values[0], &values[1] };
|
||||||
|
uint32_t *output = NULL;
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(2, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 2));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, &output, 1));
|
||||||
|
FAIL_IF(output != input[0]);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
FAIL_IF(values[0] != 11 || values[1] != 22);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestSpanBoundary(void)
|
||||||
|
{
|
||||||
|
const uint32_t input[] = { 1, 2, 3 };
|
||||||
|
uint32_t output[4];
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(4, sizeof(input[0]));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 3));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 2));
|
||||||
|
uint32_t count = 0;
|
||||||
|
uint32_t *span = SCRingBufferEnqueueSpanGet(rb, &count);
|
||||||
|
FAIL_IF_NULL(span);
|
||||||
|
FAIL_IF(count != 1 || SCRingBufferSpace(rb) != 3);
|
||||||
|
span[0] = 4;
|
||||||
|
FAIL_IF(SCRingBufferEnqueueSpanCommit(rb, 2));
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 1 || SCRingBufferSpace(rb) != 3);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 1));
|
||||||
|
span = SCRingBufferEnqueueSpanGet(rb, &count);
|
||||||
|
FAIL_IF_NULL(span);
|
||||||
|
FAIL_IF(count != 2);
|
||||||
|
span[0] = 5;
|
||||||
|
span[1] = 6;
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueueSpanCommit(rb, 2));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 4));
|
||||||
|
FAIL_IF(output[0] != 3 || output[1] != 4 || output[2] != 5 || output[3] != 6);
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SCRingBufferTestRepeatedWrap(void)
|
||||||
|
{
|
||||||
|
SCRingBuffer *rb = SCRingBufferInit(8, sizeof(uint32_t));
|
||||||
|
FAIL_IF_NULL(rb);
|
||||||
|
for (uint32_t cycle = 0; cycle < 32; cycle++) {
|
||||||
|
uint32_t input[7];
|
||||||
|
uint32_t output[4];
|
||||||
|
for (uint32_t i = 0; i < 7; i++) {
|
||||||
|
input[i] = cycle * 7 + i;
|
||||||
|
}
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input, 4));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 3));
|
||||||
|
FAIL_IF(memcmp(output, input, 3 * sizeof(input[0])) != 0);
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 1 || SCRingBufferSpace(rb) != 7);
|
||||||
|
FAIL_IF_NOT(SCRingBufferEnqueue(rb, input + 4, 3));
|
||||||
|
FAIL_IF_NOT(SCRingBufferDequeue(rb, output, 4));
|
||||||
|
FAIL_IF(memcmp(output, input + 3, sizeof(output)) != 0);
|
||||||
|
FAIL_IF(SCRingBufferCount(rb) != 0 || SCRingBufferSpace(rb) != 8);
|
||||||
|
}
|
||||||
|
SCRingBufferFree(rb);
|
||||||
|
PASS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SCRingBufferRegisterTests(void)
|
||||||
|
{
|
||||||
|
#ifdef UNITTESTS
|
||||||
|
UtRegisterTest("SCRingBufferTestInitialization", SCRingBufferTestInitialization);
|
||||||
|
UtRegisterTest("SCRingBufferTestFullCapacity", SCRingBufferTestFullCapacity);
|
||||||
|
UtRegisterTest("SCRingBufferTestWrapFifo", SCRingBufferTestWrapFifo);
|
||||||
|
UtRegisterTest("SCRingBufferTestRejectedTransfers", SCRingBufferTestRejectedTransfers);
|
||||||
|
UtRegisterTest("SCRingBufferTestZeroLength", SCRingBufferTestZeroLength);
|
||||||
|
UtRegisterTest("SCRingBufferTestWriteSpan", SCRingBufferTestWriteSpan);
|
||||||
|
UtRegisterTest("SCRingBufferTestCallerOwnership", SCRingBufferTestCallerOwnership);
|
||||||
|
UtRegisterTest("SCRingBufferTestSpanBoundary", SCRingBufferTestSpanBoundary);
|
||||||
|
UtRegisterTest("SCRingBufferTestRepeatedWrap", SCRingBufferTestRepeatedWrap);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/* Copyright (C) 2026 Open Information Security Foundation
|
||||||
|
*
|
||||||
|
* You can copy, redistribute or modify this Program under the terms of
|
||||||
|
* the GNU General Public License version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* version 2 along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SURICATA_UTIL_RING_BUFFER_H
|
||||||
|
#define SURICATA_UTIL_RING_BUFFER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Bounded FIFO of fixed-size elements, used by one thread without synchronization.
|
||||||
|
* Element contents remain owned by the caller; freeing the FIFO only frees storage. */
|
||||||
|
typedef struct SCRingBuffer_ SCRingBuffer;
|
||||||
|
|
||||||
|
/** Capacity must be a nonzero power of two and element_size must be nonzero.
|
||||||
|
* Every slot is usable. Returns NULL for invalid sizes or allocation failure. */
|
||||||
|
SCRingBuffer *SCRingBufferInit(uint32_t capacity, size_t element_size);
|
||||||
|
void SCRingBufferFree(SCRingBuffer *rb);
|
||||||
|
uint32_t SCRingBufferCount(const SCRingBuffer *rb);
|
||||||
|
uint32_t SCRingBufferSpace(const SCRingBuffer *rb);
|
||||||
|
|
||||||
|
/** Transfer all count elements or return false without changing state or output.
|
||||||
|
* Zero count succeeds for a valid buffer, including with NULL items. Nonzero
|
||||||
|
* transfers require non-NULL items that do not overlap the FIFO's storage. */
|
||||||
|
bool SCRingBufferEnqueue(SCRingBuffer *rb, const void *items, uint32_t count);
|
||||||
|
bool SCRingBufferDequeue(SCRingBuffer *rb, void *items, uint32_t count);
|
||||||
|
|
||||||
|
/** Return writable contiguous elements and their count, or NULL/count=0 if full
|
||||||
|
* or rb is NULL. count must be non-NULL. No storage is reserved, the pointer is
|
||||||
|
* valid until the next state-changing enqueue, dequeue, or commit. */
|
||||||
|
void *SCRingBufferEnqueueSpanGet(SCRingBuffer *rb, uint32_t *count);
|
||||||
|
|
||||||
|
/** Publish elements filled through EnqueueSpanGet. Reject counts beyond the current
|
||||||
|
* writable contiguous span without changing state. Zero count changes nothing. */
|
||||||
|
bool SCRingBufferEnqueueSpanCommit(SCRingBuffer *rb, uint32_t count);
|
||||||
|
|
||||||
|
void SCRingBufferRegisterTests(void);
|
||||||
|
|
||||||
|
#endif /* SURICATA_UTIL_RING_BUFFER_H */
|
||||||
Loading…
Reference in New Issue