/* +----------------------------------------------------------------------+ | 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 | +----------------------------------------------------------------------+ */ #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); } }