212 lines
5.8 KiB
C
Executable File
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);
|
|
}
|
|
}
|