2019-09-06 23:53:10 +08:00

212 lines
5.8 KiB
C
Executable File

/*
+----------------------------------------------------------------------+
| Swoole |
+----------------------------------------------------------------------+
| This source file is subject to version 2.0 of the Apache license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.apache.org/licenses/LICENSE-2.0.html |
| If you did not receive a copy of the Apache2.0 license and are unable|
| to obtain it through the world-wide-web, please send a note to |
| license@swoole.com so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: Tianfeng Han <mikan.tenny@gmail.com> |
+----------------------------------------------------------------------+
*/
#include "swoole.h"
typedef struct
{
uint8_t shared;
uint8_t status;
uint32_t size;
uint32_t alloc_offset;
uint32_t collect_offset;
uint32_t alloc_count;
sw_atomic_t free_count;
void *memory;
} swRingBuffer;
typedef struct
{
uint16_t lock;
uint16_t index;
uint32_t length;
char data[0];
} swRingBuffer_item;
static void swRingBuffer_destory(swMemoryPool *pool);
static void* swRingBuffer_alloc(swMemoryPool *pool, uint32_t size);
static void swRingBuffer_free(swMemoryPool *pool, void *ptr);
#ifdef SW_RINGBUFFER_DEBUG
static void swRingBuffer_print(swRingBuffer *object, char *prefix);
static void swRingBuffer_print(swRingBuffer *object, char *prefix)
{
printf("%s: size=%d, status=%d, alloc_count=%d, free_count=%d, offset=%d, next_offset=%d\n", prefix, object->size,
object->status, object->alloc_count, object->free_count, object->alloc_offset, object->collect_offset);
}
#endif
swMemoryPool *swRingBuffer_new(uint32_t size, uint8_t shared)
{
void *mem = (shared == 1) ? sw_shm_malloc(size) : sw_malloc(size);
if (mem == NULL)
{
swWarn("malloc(%d) failed.", size);
return NULL;
}
swRingBuffer *object = mem;
mem += sizeof(swRingBuffer);
bzero(object, sizeof(swRingBuffer));
object->size = (size - sizeof(swRingBuffer) - sizeof(swMemoryPool));
object->shared = shared;
swMemoryPool *pool = mem;
mem += sizeof(swMemoryPool);
pool->object = object;
pool->destroy = swRingBuffer_destory;
pool->free = swRingBuffer_free;
pool->alloc = swRingBuffer_alloc;
object->memory = mem;
swDebug("memory: ptr=%p", mem);
return pool;
}
static void swRingBuffer_collect(swRingBuffer *object)
{
swRingBuffer_item *item;
sw_atomic_t *free_count = &object->free_count;
int count = object->free_count;
int i;
uint32_t n_size;
for (i = 0; i < count; i++)
{
item = object->memory + object->collect_offset;
if (item->lock == 0)
{
n_size = item->length + sizeof(swRingBuffer_item);
object->collect_offset += n_size;
if (object->collect_offset + sizeof(swRingBuffer_item) >object->size || object->collect_offset >= object->size)
{
object->collect_offset = 0;
object->status = 0;
}
sw_atomic_fetch_sub(free_count, 1);
}
else
{
break;
}
}
}
static void* swRingBuffer_alloc(swMemoryPool *pool, uint32_t size)
{
assert(size > 0);
swRingBuffer *object = pool->object;
swRingBuffer_item *item;
uint32_t capacity;
uint32_t alloc_size = size + sizeof(swRingBuffer_item);
if (object->free_count > 0)
{
swRingBuffer_collect(object);
}
if (object->status == 0)
{
if (object->alloc_offset + alloc_size >= (object->size - sizeof(swRingBuffer_item)))
{
uint32_t skip_n = object->size - object->alloc_offset;
if (skip_n >= sizeof(swRingBuffer_item))
{
item = object->memory + object->alloc_offset;
item->lock = 0;
item->length = skip_n - sizeof(swRingBuffer_item);
sw_atomic_t *free_count = &object->free_count;
sw_atomic_fetch_add(free_count, 1);
}
object->alloc_offset = 0;
object->status = 1;
capacity = object->collect_offset - object->alloc_offset;
}
else
{
capacity = object->size - object->alloc_offset;
}
}
else
{
capacity = object->collect_offset - object->alloc_offset;
}
if (capacity < alloc_size)
{
return NULL;
}
item = object->memory + object->alloc_offset;
item->lock = 1;
item->length = size;
item->index = object->alloc_count;
object->alloc_offset += alloc_size;
object->alloc_count ++;
swDebug("alloc: ptr=%p", (void * )((void * )item->data - object->memory));
return item->data;
}
static void swRingBuffer_free(swMemoryPool *pool, void *ptr)
{
swRingBuffer *object = pool->object;
swRingBuffer_item *item = ptr - sizeof(swRingBuffer_item);
assert(ptr >= object->memory);
assert(ptr <= object->memory + object->size);
assert(item->lock == 1);
if (item->lock != 1)
{
swDebug("invalid free: index=%d, ptr=%p", item->index, (void * )((void * )item->data - object->memory));
}
else
{
item->lock = 0;
}
swDebug("free: ptr=%p", (void * )((void * )item->data - object->memory));
sw_atomic_t *free_count = &object->free_count;
sw_atomic_fetch_add(free_count, 1);
}
static void swRingBuffer_destory(swMemoryPool *pool)
{
swRingBuffer *object = pool->object;
if (object->shared)
{
sw_shm_free(object);
}
else
{
sw_free(object);
}
}