/**
@file
@brief 'ring' or 'circular' buffer
@details Copyright (c) 2021 Acronis International GmbH
@author Mikhail Krivtsov (mikhail.krivtsov@acronis.com)
@since $Id: $
*/
#pragma once
#include <linux/atomic.h>
#include <linux/types.h> // bool, [u]int(8|16|32|64)_t, pid_t, size_t
#ifdef KERNEL_MOCK
#include <mock/mock.h>
#endif
typedef struct {
void *buffer;
size_t item_size;
int capacity;
// 'count' is marked as atomic because it might be called from 'wait_event*' call without taking a spinlock
atomic_t count;
int count_max;
int producer_index;
int consumer_index;
} ring_t;
static inline
void ring_init(ring_t *ring, void *buffer, size_t buffer_size, size_t item_size)
{
ring->buffer = buffer;
ring->item_size = item_size;
ring->capacity = buffer_size / item_size;
atomic_set(&ring->count, 0);
ring->count_max = 0;
ring->producer_index = 0;
ring->consumer_index = 0;
}
static inline
void *ring_buffer(ring_t *ring)
{
return ring->buffer;
}
static inline
int ring_capacity(ring_t *ring)
{
return ring->capacity;
}
static inline
void ring_producer_index_move(ring_t *ring, int items)
{
int count;
ring->producer_index = (ring->producer_index + items) % ring->capacity;
count = atomic_add_return(items, &ring->count);
if (ring->count_max < count) {
ring->count_max = count;
}
}
static inline
void ring_producer_index_move_one(ring_t *ring)
{
ring_producer_index_move(ring, 1);
}
static inline
void *ring_producer_ptr(ring_t *ring)
{
return (void *) (ring->producer_index * ring->item_size + (char *)ring->buffer);
}
static inline
void ring_consumer_index_move(ring_t *ring, int items)
{
ring->consumer_index = (ring->consumer_index + items) % ring->capacity;
atomic_sub(items, &ring->count);
}
static inline
void ring_consumer_index_move_one(ring_t *ring)
{
ring_consumer_index_move(ring, 1);
}
static inline
void *ring_consumer_ptr(ring_t *ring)
{
return (void *) (ring->consumer_index * ring->item_size + (char *)ring->buffer);
}
static inline
int ring_items_count(ring_t *ring)
{
return atomic_read(&ring->count);
}
static inline
int ring_items_count_max(ring_t *ring)
{
return ring->count_max;
}
static inline
bool ring_is_empty(ring_t *ring)
{
return !ring_items_count(ring);
}
static inline
bool ring_is_full(ring_t *ring)
{
return ring_items_count(ring) >= ring->capacity;
}
|